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.15 (Berkeley) 11/04/85 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 int pt_gensym; 43 struct proc *pt_selr, *pt_selw; 44 u_char pt_send; 45 u_char pt_ucntl; 46 } pt_ioctl[NPTY]; 47 int npty = NPTY; /* for pstat -t */ 48 49 #define PF_RCOLL 0x01 50 #define PF_WCOLL 0x02 51 #define PF_NBIO 0x04 52 #define PF_PKT 0x08 /* packet mode */ 53 #define PF_STOPPED 0x10 /* user told stopped */ 54 #define PF_REMOTE 0x20 /* remote and flow controlled input */ 55 #define PF_NOSTOP 0x40 56 #define PF_UCNTL 0x80 /* user control mode */ 57 58 /*ARGSUSED*/ 59 ptsopen(dev, flag) 60 dev_t dev; 61 { 62 register struct tty *tp; 63 int error; 64 65 #ifdef lint 66 npty = npty; 67 #endif 68 if (minor(dev) >= NPTY) 69 return (ENXIO); 70 tp = &pt_tty[minor(dev)]; 71 if ((tp->t_state & TS_ISOPEN) == 0) { 72 ttychars(tp); /* Set up default chars */ 73 tp->t_ispeed = tp->t_ospeed = EXTB; 74 tp->t_flags = 0; /* No features (nor raw mode) */ 75 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 76 return (EBUSY); 77 if (tp->t_oproc) /* Ctrlr still around. */ 78 tp->t_state |= TS_CARR_ON; 79 while ((tp->t_state & TS_CARR_ON) == 0) { 80 tp->t_state |= TS_WOPEN; 81 sleep((caddr_t)&tp->t_rawq, TTIPRI); 82 } 83 error = (*linesw[tp->t_line].l_open)(dev, tp); 84 ptcwakeup(tp, FREAD|FWRITE); 85 return (error); 86 } 87 88 ptsclose(dev) 89 dev_t dev; 90 { 91 register struct tty *tp; 92 93 tp = &pt_tty[minor(dev)]; 94 (*linesw[tp->t_line].l_close)(tp); 95 ttyclose(tp); 96 ptcwakeup(tp, FREAD|FWRITE); 97 } 98 99 ptsread(dev, uio) 100 dev_t dev; 101 struct uio *uio; 102 { 103 register struct tty *tp = &pt_tty[minor(dev)]; 104 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 105 int error = 0; 106 107 again: 108 if (pti->pt_flags & PF_REMOTE) { 109 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 110 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 111 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 112 u.u_procp->p_flag&SVFORK) 113 return (EIO); 114 gsignal(u.u_procp->p_pgrp, SIGTTIN); 115 sleep((caddr_t)&lbolt, TTIPRI); 116 } 117 if (tp->t_canq.c_cc == 0) { 118 if (tp->t_state & TS_NBIO) 119 return (EWOULDBLOCK); 120 sleep((caddr_t)&tp->t_canq, TTIPRI); 121 goto again; 122 } 123 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 124 if (ureadc(getc(&tp->t_canq), uio) < 0) { 125 error = EFAULT; 126 break; 127 } 128 if (tp->t_canq.c_cc == 1) 129 (void) getc(&tp->t_canq); 130 if (tp->t_canq.c_cc) 131 return (error); 132 } else 133 if (tp->t_oproc) 134 error = (*linesw[tp->t_line].l_read)(tp, uio); 135 ptcwakeup(tp, FWRITE); 136 return (error); 137 } 138 139 /* 140 * Write to pseudo-tty. 141 * Wakeups of controlling tty will happen 142 * indirectly, when tty driver calls ptsstart. 143 */ 144 ptswrite(dev, uio) 145 dev_t dev; 146 struct uio *uio; 147 { 148 register struct tty *tp; 149 150 tp = &pt_tty[minor(dev)]; 151 if (tp->t_oproc == 0) 152 return (EIO); 153 return ((*linesw[tp->t_line].l_write)(tp, uio)); 154 } 155 156 /* 157 * Start output on pseudo-tty. 158 * Wake up process selecting or sleeping for input from controlling tty. 159 */ 160 ptsstart(tp) 161 struct tty *tp; 162 { 163 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 164 165 if (tp->t_state & TS_TTSTOP) 166 return; 167 if (pti->pt_flags & PF_STOPPED) { 168 pti->pt_flags &= ~PF_STOPPED; 169 pti->pt_send = TIOCPKT_START; 170 } 171 ptcwakeup(tp, FREAD); 172 } 173 174 ptcwakeup(tp, flag) 175 struct tty *tp; 176 { 177 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 178 179 if (flag & FREAD) { 180 if (pti->pt_selr) { 181 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 182 pti->pt_selr = 0; 183 pti->pt_flags &= ~PF_RCOLL; 184 } 185 wakeup((caddr_t)&tp->t_outq.c_cf); 186 } 187 if (flag & FWRITE) { 188 if (pti->pt_selw) { 189 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 190 pti->pt_selw = 0; 191 pti->pt_flags &= ~PF_WCOLL; 192 } 193 wakeup((caddr_t)&tp->t_rawq.c_cf); 194 } 195 } 196 197 /*ARGSUSED*/ 198 ptcopen(dev, flag) 199 dev_t dev; 200 int flag; 201 { 202 register struct tty *tp; 203 struct pt_ioctl *pti; 204 205 if (minor(dev) >= NPTY) 206 return (ENXIO); 207 tp = &pt_tty[minor(dev)]; 208 if (tp->t_oproc) 209 return (EIO); 210 tp->t_oproc = ptsstart; 211 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 212 tp->t_state |= TS_CARR_ON; 213 pti = &pt_ioctl[minor(dev)]; 214 pti->pt_flags = 0; 215 pti->pt_send = 0; 216 pti->pt_ucntl = 0; 217 return (0); 218 } 219 220 ptcclose(dev) 221 dev_t dev; 222 { 223 register struct tty *tp; 224 225 tp = &pt_tty[minor(dev)]; 226 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 227 tp->t_oproc = 0; /* mark closed */ 228 } 229 230 ptcread(dev, uio) 231 dev_t dev; 232 struct uio *uio; 233 { 234 register struct tty *tp = &pt_tty[minor(dev)]; 235 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 236 char buf[BUFSIZ]; 237 int error = 0, cc; 238 239 /* 240 * We want to block until the slave 241 * is open, and there's something to read; 242 * but if we lost the slave or we're NBIO, 243 * then return the appropriate error instead. 244 */ 245 for (;;) { 246 if (tp->t_state&TS_ISOPEN) { 247 if (pti->pt_flags&PF_PKT && pti->pt_send) { 248 error = ureadc(pti->pt_send, uio); 249 if (error) 250 return (error); 251 pti->pt_send = 0; 252 return (0); 253 } 254 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 255 error = ureadc(pti->pt_ucntl, uio); 256 if (error) 257 return (error); 258 pti->pt_ucntl = 0; 259 return (0); 260 } 261 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 262 break; 263 } 264 if ((tp->t_state&TS_CARR_ON) == 0) 265 return (EIO); 266 if (pti->pt_flags&PF_NBIO) 267 return (EWOULDBLOCK); 268 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 269 } 270 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 271 error = ureadc(0, uio); 272 while (uio->uio_resid > 0 && error == 0) { 273 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 274 if (cc <= 0) 275 break; 276 error = uiomove(buf, cc, UIO_READ, uio); 277 } 278 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 279 if (tp->t_state&TS_ASLEEP) { 280 tp->t_state &= ~TS_ASLEEP; 281 wakeup((caddr_t)&tp->t_outq); 282 } 283 if (tp->t_wsel) { 284 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 285 tp->t_wsel = 0; 286 tp->t_state &= ~TS_WCOLL; 287 } 288 } 289 return (error); 290 } 291 292 ptsstop(tp, flush) 293 register struct tty *tp; 294 int flush; 295 { 296 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 297 int flag; 298 299 /* note: FLUSHREAD and FLUSHWRITE already ok */ 300 if (flush == 0) { 301 flush = TIOCPKT_STOP; 302 pti->pt_flags |= PF_STOPPED; 303 } else 304 pti->pt_flags &= ~PF_STOPPED; 305 pti->pt_send |= flush; 306 /* change of perspective */ 307 flag = 0; 308 if (flush & FREAD) 309 flag |= FWRITE; 310 if (flush & FWRITE) 311 flag |= FREAD; 312 ptcwakeup(tp, flag); 313 } 314 315 ptcselect(dev, rw) 316 dev_t dev; 317 int rw; 318 { 319 register struct tty *tp = &pt_tty[minor(dev)]; 320 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 321 struct proc *p; 322 int s; 323 324 if ((tp->t_state&TS_CARR_ON) == 0) 325 return (1); 326 s = spl5(); 327 switch (rw) { 328 329 case FREAD: 330 if ((tp->t_state&TS_ISOPEN) && 331 (pti->pt_flags&PF_PKT && pti->pt_send || 332 pti->pt_flags&PF_UCNTL && pti->pt_ucntl || 333 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) { 334 splx(s); 335 return (1); 336 } 337 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 338 pti->pt_flags |= PF_RCOLL; 339 else 340 pti->pt_selr = u.u_procp; 341 break; 342 343 case FWRITE: 344 if ((tp->t_state&TS_ISOPEN) && 345 ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) { 346 splx(s); 347 return (1); 348 } 349 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 350 pti->pt_flags |= PF_WCOLL; 351 else 352 pti->pt_selw = u.u_procp; 353 break; 354 } 355 splx(s); 356 return (0); 357 } 358 359 ptcwrite(dev, uio) 360 dev_t dev; 361 register struct uio *uio; 362 { 363 register struct tty *tp = &pt_tty[minor(dev)]; 364 register struct iovec *iov; 365 register char *cp; 366 register int cc = 0; 367 char locbuf[BUFSIZ]; 368 int cnt = 0; 369 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 370 int error = 0; 371 372 again: 373 if ((tp->t_state&TS_ISOPEN) == 0) 374 goto block; 375 if (pti->pt_flags & PF_REMOTE) { 376 if (tp->t_canq.c_cc) 377 goto block; 378 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 379 iov = uio->uio_iov; 380 if (iov->iov_len == 0) { 381 uio->uio_iovcnt--; 382 uio->uio_iov++; 383 continue; 384 } 385 if (cc == 0) { 386 cc = MIN(iov->iov_len, BUFSIZ); 387 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); 388 cp = locbuf; 389 error = uiomove(cp, cc, UIO_WRITE, uio); 390 if (error) 391 return (error); 392 /* check again for safety */ 393 if ((tp->t_state&TS_ISOPEN) == 0) 394 return (EIO); 395 } 396 if (cc) 397 (void) b_to_q(cp, cc, &tp->t_canq); 398 cc = 0; 399 } 400 (void) putc(0, &tp->t_canq); 401 ttwakeup(tp); 402 wakeup((caddr_t)&tp->t_canq); 403 return (0); 404 } 405 while (uio->uio_iovcnt > 0) { 406 iov = uio->uio_iov; 407 if (cc == 0) { 408 if (iov->iov_len == 0) { 409 uio->uio_iovcnt--; 410 uio->uio_iov++; 411 continue; 412 } 413 cc = MIN(iov->iov_len, BUFSIZ); 414 cp = locbuf; 415 error = uiomove(cp, cc, UIO_WRITE, uio); 416 if (error) 417 return (error); 418 /* check again for safety */ 419 if ((tp->t_state&TS_ISOPEN) == 0) 420 return (EIO); 421 } 422 while (cc > 0) { 423 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 424 (tp->t_canq.c_cc > 0)) { 425 wakeup((caddr_t)&tp->t_rawq); 426 goto block; 427 } 428 (*linesw[tp->t_line].l_rint)(*cp++, tp); 429 cnt++; 430 cc--; 431 } 432 cc = 0; 433 } 434 return (0); 435 block: 436 /* 437 * Come here to wait for slave to open, for space 438 * in outq, or space in rawq. 439 */ 440 if ((tp->t_state&TS_CARR_ON) == 0) 441 return (EIO); 442 if (pti->pt_flags & PF_NBIO) { 443 iov->iov_base -= cc; 444 iov->iov_len += cc; 445 uio->uio_resid += cc; 446 uio->uio_offset -= cc; 447 if (cnt == 0) 448 return (EWOULDBLOCK); 449 return (0); 450 } 451 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 452 goto again; 453 } 454 455 /*ARGSUSED*/ 456 ptyioctl(dev, cmd, data, flag) 457 caddr_t data; 458 dev_t dev; 459 { 460 register struct tty *tp = &pt_tty[minor(dev)]; 461 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 462 int stop, error; 463 extern ttyinput(); 464 465 /* 466 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 467 * ttywflush(tp) will hang if there are characters in the outq. 468 */ 469 if (cdevsw[major(dev)].d_open == ptcopen) 470 switch (cmd) { 471 472 case TIOCPKT: 473 if (*(int *)data) { 474 if (pti->pt_flags & PF_UCNTL) 475 return (EINVAL); 476 pti->pt_flags |= PF_PKT; 477 } else 478 pti->pt_flags &= ~PF_PKT; 479 return (0); 480 481 case TIOCUCNTL: 482 if (*(int *)data) { 483 if (pti->pt_flags & PF_PKT) 484 return (EINVAL); 485 pti->pt_flags |= PF_UCNTL; 486 } else 487 pti->pt_flags &= ~PF_UCNTL; 488 return (0); 489 490 case TIOCREMOTE: 491 if (*(int *)data) 492 pti->pt_flags |= PF_REMOTE; 493 else 494 pti->pt_flags &= ~PF_REMOTE; 495 ttyflush(tp, FREAD|FWRITE); 496 return (0); 497 498 case FIONBIO: 499 if (*(int *)data) 500 pti->pt_flags |= PF_NBIO; 501 else 502 pti->pt_flags &= ~PF_NBIO; 503 return (0); 504 505 case TIOCSETP: 506 case TIOCSETN: 507 case TIOCSETD: 508 while (getc(&tp->t_outq) >= 0) 509 ; 510 break; 511 } 512 error = ttioctl(tp, cmd, data, flag); 513 /* 514 * Since we use the tty queues internally, 515 * pty's can't be switched to disciplines which overwrite 516 * the queues. We can't tell anything about the discipline 517 * from here... 518 */ 519 if (linesw[tp->t_line].l_rint != ttyinput) { 520 (*linesw[tp->t_line].l_close)(tp); 521 tp->t_line = 0; 522 (void)(*linesw[tp->t_line].l_open)(dev, tp); 523 error = ENOTTY; 524 } 525 if (error < 0) { 526 if (pti->pt_flags & PF_UCNTL && 527 (cmd & ~0xff) == _IO(u,0)) { 528 if (cmd & 0xff) { 529 pti->pt_ucntl = (u_char)cmd; 530 ptcwakeup(tp, FREAD); 531 } 532 return (0); 533 } 534 error = ENOTTY; 535 } 536 stop = (tp->t_flags & RAW) == 0 && 537 tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q); 538 if (pti->pt_flags & PF_NOSTOP) { 539 if (stop) { 540 pti->pt_send &= TIOCPKT_NOSTOP; 541 pti->pt_send |= TIOCPKT_DOSTOP; 542 pti->pt_flags &= ~PF_NOSTOP; 543 ptcwakeup(tp, FREAD); 544 } 545 } else { 546 if (!stop) { 547 pti->pt_send &= ~TIOCPKT_DOSTOP; 548 pti->pt_send |= TIOCPKT_NOSTOP; 549 pti->pt_flags |= PF_NOSTOP; 550 ptcwakeup(tp, FREAD); 551 } 552 } 553 return (error); 554 } 555 #endif 556