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.12 (Berkeley) 06/08/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_state & TS_ISOPEN) 231 gsignal(tp->t_pgrp, SIGHUP); 232 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 233 ttyflush(tp, FREAD|FWRITE); 234 tp->t_oproc = 0; /* mark closed */ 235 } 236 237 ptcread(dev, uio) 238 dev_t dev; 239 struct uio *uio; 240 { 241 register struct tty *tp = &pt_tty[minor(dev)]; 242 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 243 char buf[BUFSIZ]; 244 int error = 0, cc; 245 246 /* 247 * We want to block until the slave 248 * is open, and there's something to read; 249 * but if we lost the slave or we're NBIO, 250 * then return the appropriate error instead. 251 */ 252 for (;;) { 253 if (tp->t_state&TS_ISOPEN) { 254 if (pti->pt_flags&PF_PKT && pti->pt_send) { 255 error = ureadc(pti->pt_send, uio); 256 if (error) 257 return (error); 258 pti->pt_send = 0; 259 return (0); 260 } 261 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 262 error = ureadc(pti->pt_ucntl, uio); 263 if (error) 264 return (error); 265 pti->pt_ucntl = 0; 266 return (0); 267 } 268 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 269 break; 270 } 271 if ((tp->t_state&TS_CARR_ON) == 0) 272 return (EIO); 273 if (pti->pt_flags&PF_NBIO) 274 return (EWOULDBLOCK); 275 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 276 } 277 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 278 error = ureadc(0, uio); 279 while (uio->uio_resid > 0 && error == 0) { 280 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 281 if (cc <= 0) 282 break; 283 error = uiomove(buf, cc, UIO_READ, uio); 284 } 285 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 286 if (tp->t_state&TS_ASLEEP) { 287 tp->t_state &= ~TS_ASLEEP; 288 wakeup((caddr_t)&tp->t_outq); 289 } 290 if (tp->t_wsel) { 291 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 292 tp->t_wsel = 0; 293 tp->t_state &= ~TS_WCOLL; 294 } 295 } 296 return (error); 297 } 298 299 ptsstop(tp, flush) 300 register struct tty *tp; 301 int flush; 302 { 303 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 304 int flag; 305 306 /* note: FLUSHREAD and FLUSHWRITE already ok */ 307 if (flush == 0) { 308 flush = TIOCPKT_STOP; 309 pti->pt_flags |= PF_STOPPED; 310 } else 311 pti->pt_flags &= ~PF_STOPPED; 312 pti->pt_send |= flush; 313 /* change of perspective */ 314 flag = 0; 315 if (flush & FREAD) 316 flag |= FWRITE; 317 if (flush & FWRITE) 318 flag |= FREAD; 319 ptcwakeup(tp, flush); 320 } 321 322 ptcselect(dev, rw) 323 dev_t dev; 324 int rw; 325 { 326 register struct tty *tp = &pt_tty[minor(dev)]; 327 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 328 struct proc *p; 329 int s; 330 331 if ((tp->t_state&TS_CARR_ON) == 0) 332 return (1); 333 s = spl5(); 334 switch (rw) { 335 336 case FREAD: 337 if ((tp->t_state&TS_ISOPEN) && 338 (pti->pt_flags&PF_PKT && pti->pt_send || 339 pti->pt_flags&PF_UCNTL && pti->pt_ucntl || 340 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) { 341 splx(s); 342 return (1); 343 } 344 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 345 pti->pt_flags |= PF_RCOLL; 346 else 347 pti->pt_selr = u.u_procp; 348 break; 349 350 case FWRITE: 351 if ((tp->t_state&TS_ISOPEN) && 352 ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) { 353 splx(s); 354 return (1); 355 } 356 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 357 pti->pt_flags |= PF_WCOLL; 358 else 359 pti->pt_selw = u.u_procp; 360 break; 361 } 362 splx(s); 363 return (0); 364 } 365 366 ptcwrite(dev, uio) 367 dev_t dev; 368 register struct uio *uio; 369 { 370 register struct tty *tp = &pt_tty[minor(dev)]; 371 register struct iovec *iov; 372 register char *cp; 373 register int cc = 0; 374 char locbuf[BUFSIZ]; 375 int cnt = 0; 376 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 377 int error = 0; 378 379 again: 380 if ((tp->t_state&TS_ISOPEN) == 0) 381 goto block; 382 if (cnt == 0 && pti->pt_flags & PF_REMOTE) { 383 if (uio->uio_iovcnt <= 0) 384 return (0); 385 if (tp->t_canq.c_cc) 386 goto block; 387 iov = uio->uio_iov; 388 if (cc == 0 && iov->iov_len) { 389 cc = MIN(iov->iov_len, BUFSIZ); 390 cp = locbuf; 391 error = uiomove(cp, cc, UIO_WRITE, uio); 392 if (error) 393 return (error); 394 /* check again for safety */ 395 if ((tp->t_state&TS_ISOPEN) == 0) 396 return (EIO); 397 if (tp->t_canq.c_cc) 398 goto block; 399 } 400 if (cc) 401 (void) b_to_q(cp, cc, &tp->t_canq); 402 (void) putc(0, &tp->t_canq); 403 ttwakeup(tp); 404 wakeup((caddr_t)&tp->t_canq); 405 return (0); 406 } 407 while (uio->uio_iovcnt > 0) { 408 iov = uio->uio_iov; 409 if (cc == 0) { 410 if (iov->iov_len == 0) { 411 uio->uio_iovcnt--; 412 uio->uio_iov++; 413 continue; 414 } 415 cc = MIN(iov->iov_len, BUFSIZ); 416 cp = locbuf; 417 error = uiomove(cp, cc, UIO_WRITE, uio); 418 if (error) 419 return (error); 420 /* check again for safety */ 421 if ((tp->t_state&TS_ISOPEN) == 0) 422 return (EIO); 423 } 424 while (--cc >= 0) { 425 (*linesw[tp->t_line].l_rint)(*cp++, tp); 426 cnt++; 427 } 428 cc = 0; 429 } 430 return (0); 431 block: 432 /* 433 * Come here to wait for slave to open or for space 434 * in outq. 435 */ 436 if ((tp->t_state&TS_CARR_ON) == 0) 437 return (EIO); 438 if (pti->pt_flags & PF_NBIO) { 439 if (cnt == 0) 440 return (EWOULDBLOCK); 441 iov->iov_base -= cc; 442 iov->iov_len += cc; 443 uio->uio_resid += cc; 444 uio->uio_offset -= cc; 445 return (0); 446 } 447 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 448 goto again; 449 } 450 451 /*ARGSUSED*/ 452 ptyioctl(dev, cmd, data, flag) 453 caddr_t data; 454 dev_t dev; 455 { 456 register struct tty *tp = &pt_tty[minor(dev)]; 457 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 458 int stop, error; 459 460 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 461 if (cdevsw[major(dev)].d_open == ptcopen) 462 switch (cmd) { 463 464 case TIOCPKT: 465 if (*(int *)data) { 466 if (pti->pt_flags & PF_UCNTL) 467 return (EINVAL); 468 pti->pt_flags |= PF_PKT; 469 } else 470 pti->pt_flags &= ~PF_PKT; 471 return (0); 472 473 case TIOCUCNTL: 474 if (*(int *)data) { 475 if (pti->pt_flags & PF_PKT) 476 return (EINVAL); 477 pti->pt_flags |= PF_UCNTL; 478 } else 479 pti->pt_flags &= ~PF_UCNTL; 480 return (0); 481 482 case TIOCREMOTE: 483 if (*(int *)data) 484 pti->pt_flags |= PF_REMOTE; 485 else 486 pti->pt_flags &= ~PF_REMOTE; 487 ttyflush(tp, FREAD|FWRITE); 488 return (0); 489 490 case FIONBIO: 491 if (*(int *)data) 492 pti->pt_flags |= PF_NBIO; 493 else 494 pti->pt_flags &= ~PF_NBIO; 495 return (0); 496 497 case TIOCSETP: 498 while (getc(&tp->t_outq) >= 0) 499 ; 500 break; 501 } 502 error = ttioctl(tp, cmd, data, flag); 503 if (error < 0) { 504 if (pti->pt_flags & PF_UCNTL && 505 (cmd & ~0xff) == _IO(u,0)) { 506 if (cmd & 0xff) { 507 pti->pt_ucntl = (u_char)cmd; 508 ptcwakeup(tp, FREAD); 509 } 510 return (0); 511 } 512 error = ENOTTY; 513 } 514 stop = (tp->t_flags & RAW) == 0 && 515 tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q); 516 if (pti->pt_flags & PF_NOSTOP) { 517 if (stop) { 518 pti->pt_send &= TIOCPKT_NOSTOP; 519 pti->pt_send |= TIOCPKT_DOSTOP; 520 pti->pt_flags &= ~PF_NOSTOP; 521 ptcwakeup(tp, FREAD); 522 } 523 } else { 524 if (!stop) { 525 pti->pt_send &= ~TIOCPKT_DOSTOP; 526 pti->pt_send |= TIOCPKT_NOSTOP; 527 pti->pt_flags |= PF_NOSTOP; 528 ptcwakeup(tp, FREAD); 529 } 530 } 531 return (error); 532 } 533 #endif 534