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