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

Defined functions

ptcclose defined in line 219; never used
ptcopen defined in line 197; used 1 times
ptcread defined in line 229; never used
ptcselect defined in line 314; never used
ptcwakeup defined in line 173; used 8 times
ptcwrite defined in line 375; never used
ptsclose defined in line 87; never used
ptsopen defined in line 58; never used
ptsread defined in line 98; never used
ptsstart defined in line 159; used 1 times
ptsstop defined in line 291; never used
ptswrite defined in line 143; never used
ptyioctl defined in line 473; never used

Defined variables

npty defined in line 46; used 2 times
  • in line 65(2)
pt_ioctl defined in line 45; used 9 times
pt_tty defined in line 39; used 10 times

Defined struct's

pt_ioctl defined in line 40; used 18 times

Defined macros

BUFSIZ defined in line 33; used 5 times
NPTY defined in line 30; used 8 times
PF_NBIO defined in line 50; used 4 times
PF_NOSTOP defined in line 54; used 3 times
PF_PKT defined in line 51; used 6 times
PF_RCOLL defined in line 48; used 3 times
PF_REMOTE defined in line 53; used 5 times
PF_STOPPED defined in line 52; used 4 times
PF_UCNTL defined in line 55; used 7 times
PF_WCOLL defined in line 49; used 3 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1856
Valid CSS Valid XHTML 1.0 Strict