The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_pty.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: tty_pty.c,v 1.112.4.1 2009/06/17 20:17:37 bouyer Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1982, 1986, 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)tty_pty.c   8.4 (Berkeley) 2/20/95
   32  */
   33 
   34 /*
   35  * Pseudo-teletype Driver
   36  * (Actually two drivers, requiring two entries in 'cdevsw')
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: tty_pty.c,v 1.112.4.1 2009/06/17 20:17:37 bouyer Exp $");
   41 
   42 #include "opt_compat_sunos.h"
   43 #include "opt_ptm.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/ioctl.h>
   48 #include <sys/proc.h>
   49 #include <sys/tty.h>
   50 #include <sys/stat.h>
   51 #include <sys/file.h>
   52 #include <sys/kernel.h>
   53 #include <sys/vnode.h>
   54 #include <sys/namei.h>
   55 #include <sys/signalvar.h>
   56 #include <sys/uio.h>
   57 #include <sys/filedesc.h>
   58 #include <sys/conf.h>
   59 #include <sys/poll.h>
   60 #include <sys/malloc.h>
   61 #include <sys/pty.h>
   62 #include <sys/kauth.h>
   63 
   64 #define DEFAULT_NPTYS           16      /* default number of initial ptys */
   65 #define DEFAULT_MAXPTYS         992     /* default maximum number of ptys */
   66 
   67 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
   68 
   69 struct  pt_softc {
   70         struct  tty *pt_tty;
   71         int     pt_flags;
   72         struct  selinfo pt_selr, pt_selw;
   73         u_char  pt_send;
   74         u_char  pt_ucntl;
   75 };
   76 
   77 static struct pt_softc **pt_softc = NULL;       /* pty array */
   78 static int maxptys = DEFAULT_MAXPTYS;   /* maximum number of ptys (sysctable) */
   79 kmutex_t pt_softc_mutex;
   80 int npty = 0;                   /* for pstat -t */
   81 
   82 #define PF_PKT          0x08            /* packet mode */
   83 #define PF_STOPPED      0x10            /* user told stopped */
   84 #define PF_REMOTE       0x20            /* remote and flow controlled input */
   85 #define PF_NOSTOP       0x40
   86 #define PF_UCNTL        0x80            /* user control mode */
   87 
   88 void    ptyattach(int);
   89 void    ptcwakeup(struct tty *, int);
   90 void    ptsstart(struct tty *);
   91 int     pty_maxptys(int, int);
   92 
   93 static struct pt_softc **ptyarralloc(int);
   94 
   95 dev_type_open(ptcopen);
   96 dev_type_close(ptcclose);
   97 dev_type_read(ptcread);
   98 dev_type_write(ptcwrite);
   99 dev_type_poll(ptcpoll);
  100 dev_type_kqfilter(ptckqfilter);
  101 
  102 dev_type_open(ptsopen);
  103 dev_type_close(ptsclose);
  104 dev_type_read(ptsread);
  105 dev_type_write(ptswrite);
  106 dev_type_stop(ptsstop);
  107 dev_type_poll(ptspoll);
  108 
  109 dev_type_ioctl(ptyioctl);
  110 dev_type_tty(ptytty);
  111 
  112 const struct cdevsw ptc_cdevsw = {
  113         ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
  114         nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
  115 };
  116 
  117 const struct cdevsw pts_cdevsw = {
  118         ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
  119         ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
  120 };
  121 
  122 #if defined(pmax)
  123 const struct cdevsw ptc_ultrix_cdevsw = {
  124         ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
  125         nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
  126 };
  127 
  128 const struct cdevsw pts_ultrix_cdevsw = {
  129         ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
  130         ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
  131 };
  132 #endif /* defined(pmax) */
  133 
  134 /*
  135  * Check if a pty is free to use.
  136  */
  137 int
  138 pty_isfree(int minor, int lock)
  139 {
  140         struct pt_softc *pt = pt_softc[minor];
  141         if (lock)
  142                 mutex_enter(&pt_softc_mutex);
  143         minor = pt == NULL || pt->pt_tty == NULL ||
  144             pt->pt_tty->t_oproc == NULL;
  145         if (lock)
  146                 mutex_exit(&pt_softc_mutex);
  147         return minor;
  148 }
  149 
  150 /*
  151  * Allocate and zero array of nelem elements.
  152  */
  153 static struct pt_softc **
  154 ptyarralloc(nelem)
  155         int nelem;
  156 {
  157         struct pt_softc **pt;
  158         nelem += 10;
  159         pt = malloc(nelem * sizeof *pt, M_DEVBUF, M_WAITOK | M_ZERO);
  160         return pt;
  161 }
  162 
  163 /*
  164  * Check if the minor is correct and ensure necessary structures
  165  * are properly allocated.
  166  */
  167 int
  168 pty_check(int ptn)
  169 {
  170         struct pt_softc *pti;
  171 
  172         if (ptn >= npty) {
  173                 struct pt_softc **newpt, **oldpt;
  174                 int newnpty;
  175 
  176                 /* check if the requested pty can be granted */
  177                 if (ptn >= maxptys) {
  178             limit_reached:
  179                         tablefull("pty", "increase kern.maxptys");
  180                         return (ENXIO);
  181                 }
  182 
  183                 /* Allocate a larger pty array */
  184                 for (newnpty = npty; newnpty <= ptn;)
  185                         newnpty *= 2;
  186                 if (newnpty > maxptys)
  187                         newnpty = maxptys;
  188                 newpt = ptyarralloc(newnpty);
  189 
  190                 /*
  191                  * Now grab the pty array mutex - we need to ensure
  192                  * that the pty array is consistent while copying it's
  193                  * content to newly allocated, larger space; we also
  194                  * need to be safe against pty_maxptys().
  195                  */
  196                 mutex_enter(&pt_softc_mutex);
  197 
  198                 if (newnpty >= maxptys) {
  199                         /* limit cut away beneath us... */
  200                         newnpty = maxptys;
  201                         if (ptn >= newnpty) {
  202                                 mutex_exit(&pt_softc_mutex);
  203                                 free(newpt, M_DEVBUF);
  204                                 goto limit_reached;
  205                         }
  206                 }
  207 
  208                 /*
  209                  * If the pty array was not enlarged while we were waiting
  210                  * for mutex, copy current contents of pt_softc[] to newly
  211                  * allocated array and start using the new bigger array.
  212                  */
  213                 if (newnpty > npty) {
  214                         memcpy(newpt, pt_softc, npty*sizeof(struct pt_softc *));
  215                         oldpt = pt_softc;
  216                         pt_softc = newpt;
  217                         npty = newnpty;
  218                 } else {
  219                         /* was enlarged when waited for lock, free new space */
  220                         oldpt = newpt;
  221                 }
  222 
  223                 mutex_exit(&pt_softc_mutex);
  224                 free(oldpt, M_DEVBUF);
  225         }
  226 
  227         /*
  228          * If the entry is not yet allocated, allocate one. The mutex is
  229          * needed so that the state of pt_softc[] array is consistant
  230          * in case it has been lengthened above.
  231          */
  232         if (!pt_softc[ptn]) {
  233                 pti = malloc(sizeof(struct pt_softc),
  234                     M_DEVBUF, M_WAITOK | M_ZERO);
  235 
  236                 selinit(&pti->pt_selr);
  237                 selinit(&pti->pt_selw);
  238                 pti->pt_tty = ttymalloc();
  239 
  240                 mutex_enter(&pt_softc_mutex);
  241 
  242                 /*
  243                  * Check the entry again - it might have been
  244                  * added while we were waiting for mutex.
  245                  */
  246                 if (pt_softc[ptn]) {
  247                         mutex_exit(&pt_softc_mutex);
  248                         ttyfree(pti->pt_tty);
  249                         seldestroy(&pti->pt_selr);
  250                         seldestroy(&pti->pt_selw);
  251                         free(pti, M_DEVBUF);
  252                         return (0);
  253                 }
  254                 tty_attach(pti->pt_tty);
  255                 pt_softc[ptn] = pti;
  256 
  257                 mutex_exit(&pt_softc_mutex);
  258         }
  259 
  260         return (0);
  261 }
  262 
  263 /*
  264  * Set maxpty in thread-safe way. Returns 0 in case of error, otherwise
  265  * new value of maxptys.
  266  */
  267 int
  268 pty_maxptys(newmax, set)
  269         int newmax, set;
  270 {
  271         if (!set)
  272                 return (maxptys);
  273 
  274         /*
  275          * We have to grab the pt_softc lock, so that we would pick correct
  276          * value of npty (might be modified in pty_check()).
  277          */
  278         mutex_enter(&pt_softc_mutex);
  279 
  280         /*
  281          * The value cannot be set to value lower than the highest pty
  282          * number ever allocated.
  283          */
  284         if (newmax >= npty)
  285                 maxptys = newmax;
  286         else
  287                 newmax = 0;
  288 
  289         mutex_exit(&pt_softc_mutex);
  290 
  291         return newmax;
  292 }
  293 
  294 /*
  295  * Establish n (or default if n is 1) ptys in the system.
  296  */
  297 void
  298 ptyattach(n)
  299         int n;
  300 {
  301 
  302         mutex_init(&pt_softc_mutex, MUTEX_DEFAULT, IPL_NONE);
  303 
  304         /* maybe should allow 0 => none? */
  305         if (n <= 1)
  306                 n = DEFAULT_NPTYS;
  307         pt_softc = ptyarralloc(n);
  308         npty = n;
  309 #ifndef NO_DEV_PTM
  310         ptmattach(1);
  311 #endif
  312 }
  313 
  314 /*ARGSUSED*/
  315 int
  316 ptsopen(dev_t dev, int flag, int devtype, struct lwp *l)
  317 {
  318         struct pt_softc *pti;
  319         struct tty *tp;
  320         int error;
  321         int ptn = minor(dev);
  322 
  323         if ((error = pty_check(ptn)) != 0)
  324                 return (error);
  325 
  326         mutex_spin_enter(&tty_lock);
  327         pti = pt_softc[ptn];
  328         tp = pti->pt_tty;
  329         if (!ISSET(tp->t_state, TS_ISOPEN)) {
  330                 ttychars(tp);           /* Set up default chars */
  331                 tp->t_iflag = TTYDEF_IFLAG;
  332                 tp->t_oflag = TTYDEF_OFLAG;
  333                 tp->t_lflag = TTYDEF_LFLAG;
  334                 tp->t_cflag = TTYDEF_CFLAG;
  335                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  336                 ttsetwater(tp);         /* would be done in xxparam() */
  337         } else if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN,
  338             tp) != 0) {
  339                 mutex_spin_exit(&tty_lock);
  340                 return (EBUSY);
  341         }
  342         if (tp->t_oproc)                        /* Ctrlr still around. */
  343                 SET(tp->t_state, TS_CARR_ON);
  344         if (!ISSET(flag, O_NONBLOCK)) {
  345                 while (!ISSET(tp->t_state, TS_CARR_ON)) {
  346                         tp->t_wopen++;
  347                         error = ttysleep(tp, &tp->t_rawcv, true, 0);
  348                         tp->t_wopen--;
  349                         if (error) {
  350                                 mutex_spin_exit(&tty_lock);
  351                                 return (error);
  352                         }
  353                 }
  354         }
  355         mutex_spin_exit(&tty_lock);
  356         error = (*tp->t_linesw->l_open)(dev, tp);
  357         ptcwakeup(tp, FREAD|FWRITE);
  358         return (error);
  359 }
  360 
  361 int
  362 ptsclose(dev_t dev, int flag, int mode, struct lwp *l)
  363 {
  364         struct pt_softc *pti = pt_softc[minor(dev)];
  365         struct tty *tp = pti->pt_tty;
  366         int error;
  367 
  368         error = (*tp->t_linesw->l_close)(tp, flag);
  369         error |= ttyclose(tp);
  370         ptcwakeup(tp, FREAD|FWRITE);
  371         return (error);
  372 }
  373 
  374 int
  375 ptsread(dev, uio, flag)
  376         dev_t dev;
  377         struct uio *uio;
  378         int flag;
  379 {
  380         struct proc *p = curproc;
  381         struct pt_softc *pti = pt_softc[minor(dev)];
  382         struct tty *tp = pti->pt_tty;
  383         int error = 0;
  384         int cc, c;
  385 
  386 again:
  387         if (pti->pt_flags & PF_REMOTE) {
  388                 mutex_spin_enter(&tty_lock);
  389                 while (isbackground(p, tp)) {   /* XXXSMP */
  390                         if (sigismasked(curlwp, SIGTTIN) ||
  391                             p->p_pgrp->pg_jobc == 0 ||
  392                             p->p_lflag & PL_PPWAIT) {
  393                                 mutex_spin_exit(&tty_lock);
  394                                 return (EIO);
  395                         }
  396                         ttysig(tp, TTYSIG_PG1, SIGTTIN);
  397                         error = ttysleep(tp, &lbolt, true, 0);
  398                         if (error) {
  399                                 mutex_spin_exit(&tty_lock);
  400                                 return (error);
  401                         }
  402                 }
  403                 if (tp->t_canq.c_cc == 0) {
  404                         if (flag & IO_NDELAY) {
  405                                 mutex_spin_exit(&tty_lock);
  406                                 return (EWOULDBLOCK);
  407                         }
  408                         error = ttysleep(tp, &tp->t_cancv, true, 0);
  409                         mutex_spin_exit(&tty_lock);
  410                         if (error)
  411                                 return (error);
  412                         goto again;
  413                 }
  414                 while(error == 0 && tp->t_canq.c_cc > 1 && uio->uio_resid > 0) {
  415                         c = getc(&tp->t_canq);
  416                         mutex_spin_exit(&tty_lock);
  417                         error = ureadc(c, uio);
  418                         mutex_spin_enter(&tty_lock);
  419                         /* Re-check terminal state here? */
  420                 }
  421                 if (tp->t_canq.c_cc == 1)
  422                         (void) getc(&tp->t_canq);
  423                 cc = tp->t_canq.c_cc;
  424                 mutex_spin_exit(&tty_lock);
  425                 if (cc)
  426                         return (error);
  427         } else if (tp->t_oproc)
  428                 error = (*tp->t_linesw->l_read)(tp, uio, flag);
  429         ptcwakeup(tp, FWRITE);
  430         return (error);
  431 }
  432 
  433 /*
  434  * Write to pseudo-tty.
  435  * Wakeups of controlling tty will happen
  436  * indirectly, when tty driver calls ptsstart.
  437  */
  438 int
  439 ptswrite(dev, uio, flag)
  440         dev_t dev;
  441         struct uio *uio;
  442         int flag;
  443 {
  444         struct pt_softc *pti = pt_softc[minor(dev)];
  445         struct tty *tp = pti->pt_tty;
  446 
  447         if (tp->t_oproc == 0)
  448                 return (EIO);
  449         return ((*tp->t_linesw->l_write)(tp, uio, flag));
  450 }
  451 
  452 /*
  453  * Poll pseudo-tty.
  454  */
  455 int
  456 ptspoll(dev, events, l)
  457         dev_t dev;
  458         int events;
  459         struct lwp *l;
  460 {
  461         struct pt_softc *pti = pt_softc[minor(dev)];
  462         struct tty *tp = pti->pt_tty;
  463 
  464         if (tp->t_oproc == 0)
  465                 return (POLLHUP);
  466 
  467         return ((*tp->t_linesw->l_poll)(tp, events, l));
  468 }
  469 
  470 /*
  471  * Start output on pseudo-tty.
  472  * Wake up process polling or sleeping for input from controlling tty.
  473  */
  474 void
  475 ptsstart(tp)
  476         struct tty *tp;
  477 {
  478         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  479 
  480         KASSERT(mutex_owned(&tty_lock));
  481 
  482         if (ISSET(tp->t_state, TS_TTSTOP))
  483                 return;
  484         if (pti->pt_flags & PF_STOPPED) {
  485                 pti->pt_flags &= ~PF_STOPPED;
  486                 pti->pt_send = TIOCPKT_START;
  487         }
  488 
  489         selnotify(&pti->pt_selr, 0, NOTE_SUBMIT);
  490         cv_broadcast(&tp->t_outcvf);
  491 }
  492 
  493 /*
  494  * Stop output.
  495  */
  496 void
  497 ptsstop(tp, flush)
  498         struct tty *tp;
  499         int flush;
  500 {
  501         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  502 
  503         KASSERT(mutex_owned(&tty_lock));
  504 
  505         /* note: FLUSHREAD and FLUSHWRITE already ok */
  506         if (flush == 0) {
  507                 flush = TIOCPKT_STOP;
  508                 pti->pt_flags |= PF_STOPPED;
  509         } else
  510                 pti->pt_flags &= ~PF_STOPPED;
  511         pti->pt_send |= flush;
  512 
  513         /* change of perspective */
  514         if (flush & FREAD) {
  515                 selnotify(&pti->pt_selw, 0, NOTE_SUBMIT);
  516                 cv_broadcast(&tp->t_rawcvf);
  517         }
  518         if (flush & FWRITE) {
  519                 selnotify(&pti->pt_selr, 0, NOTE_SUBMIT);
  520                 cv_broadcast(&tp->t_outcvf);
  521         }
  522 }
  523 
  524 void
  525 ptcwakeup(tp, flag)
  526         struct tty *tp;
  527         int flag;
  528 {
  529         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  530 
  531         mutex_spin_enter(&tty_lock);
  532         if (flag & FREAD) {
  533                 selnotify(&pti->pt_selr, 0, NOTE_SUBMIT);
  534                 cv_broadcast(&tp->t_outcvf);
  535         }
  536         if (flag & FWRITE) {
  537                 selnotify(&pti->pt_selw, 0, NOTE_SUBMIT);
  538                 cv_broadcast(&tp->t_rawcvf);
  539         }
  540         mutex_spin_exit(&tty_lock);
  541 }
  542 
  543 /*ARGSUSED*/
  544 int
  545 ptcopen(dev_t dev, int flag, int devtype, struct lwp *l)
  546 {
  547         struct pt_softc *pti;
  548         struct tty *tp;
  549         int error;
  550         int ptn = minor(dev);
  551 
  552         if ((error = pty_check(ptn)) != 0)
  553                 return (error);
  554 
  555         pti = pt_softc[ptn];
  556         tp = pti->pt_tty;
  557 
  558         mutex_spin_enter(&tty_lock);
  559         if (tp->t_oproc) {
  560                 mutex_spin_exit(&tty_lock);
  561                 return (EIO);
  562         }
  563         tp->t_oproc = ptsstart;
  564         mutex_spin_exit(&tty_lock);
  565         (void)(*tp->t_linesw->l_modem)(tp, 1);
  566         CLR(tp->t_lflag, EXTPROC);
  567         pti->pt_flags = 0;
  568         pti->pt_send = 0;
  569         pti->pt_ucntl = 0;
  570         return (0);
  571 }
  572 
  573 /*ARGSUSED*/
  574 int
  575 ptcclose(dev_t dev, int flag, int devtype, struct lwp *l)
  576 {
  577         struct pt_softc *pti = pt_softc[minor(dev)];
  578         struct tty *tp = pti->pt_tty;
  579 
  580         (void)(*tp->t_linesw->l_modem)(tp, 0);
  581         mutex_spin_enter(&tty_lock);
  582         CLR(tp->t_state, TS_CARR_ON);
  583         tp->t_oproc = 0;                /* mark closed */
  584         mutex_spin_exit(&tty_lock);
  585         return (0);
  586 }
  587 
  588 int
  589 ptcread(dev, uio, flag)
  590         dev_t dev;
  591         struct uio *uio;
  592         int flag;
  593 {
  594         struct pt_softc *pti = pt_softc[minor(dev)];
  595         struct tty *tp = pti->pt_tty;
  596         u_char bf[BUFSIZ];
  597         int error = 0, cc;
  598 
  599         /*
  600          * We want to block until the slave
  601          * is open, and there's something to read;
  602          * but if we lost the slave or we're NBIO,
  603          * then return the appropriate error instead.
  604          */
  605         mutex_spin_enter(&tty_lock);
  606         for (;;) {
  607                 if (ISSET(tp->t_state, TS_ISOPEN)) {
  608                         if (pti->pt_flags & PF_PKT && pti->pt_send) {
  609                                 mutex_spin_exit(&tty_lock);
  610                                 error = ureadc((int)pti->pt_send, uio);
  611                                 if (error)
  612                                         return (error);
  613                                 /*
  614                                  * Since we don't have the tty locked, there's
  615                                  * a risk of messing up `t_termios'. This is
  616                                  * relevant only if the tty got closed and then
  617                                  * opened again while we were out uiomoving.
  618                                  */
  619                                 if (pti->pt_send & TIOCPKT_IOCTL) {
  620                                         cc = min(uio->uio_resid,
  621                                                 sizeof(tp->t_termios));
  622                                         uiomove((void *) &tp->t_termios,
  623                                                 cc, uio);
  624                                 }
  625                                 pti->pt_send = 0;
  626                                 return (0);
  627                         }
  628                         if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
  629                                 mutex_spin_exit(&tty_lock);
  630                                 error = ureadc((int)pti->pt_ucntl, uio);
  631                                 if (error)
  632                                         return (error);
  633                                 pti->pt_ucntl = 0;
  634                                 return (0);
  635                         }
  636                         if (tp->t_outq.c_cc && !ISSET(tp->t_state, TS_TTSTOP))
  637                                 break;
  638                 }
  639                 if (!ISSET(tp->t_state, TS_CARR_ON)) {
  640                         error = 0;      /* EOF */
  641                         goto out;
  642                 }
  643                 if (flag & IO_NDELAY) {
  644                         error = EWOULDBLOCK;
  645                         goto out;
  646                 }
  647                 error = cv_wait_sig(&tp->t_outcvf, &tty_lock);
  648                 if (error)
  649                         goto out;
  650         }
  651 
  652         if (pti->pt_flags & (PF_PKT|PF_UCNTL)) {
  653                 mutex_spin_exit(&tty_lock);
  654                 error = ureadc(0, uio);
  655                 mutex_spin_enter(&tty_lock);
  656                 if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
  657                         error = EIO;
  658         }
  659         while (uio->uio_resid > 0 && error == 0) {
  660                 cc = q_to_b(&tp->t_outq, bf, min(uio->uio_resid, BUFSIZ));
  661                 if (cc <= 0)
  662                         break;
  663                 mutex_spin_exit(&tty_lock);
  664                 error = uiomove(bf, cc, uio);
  665                 mutex_spin_enter(&tty_lock);
  666                 if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
  667                         error = EIO;
  668         }
  669         ttypull(tp);
  670 out:
  671         mutex_spin_exit(&tty_lock);
  672         return (error);
  673 }
  674 
  675 
  676 int
  677 ptcwrite(dev, uio, flag)
  678         dev_t dev;
  679         struct uio *uio;
  680         int flag;
  681 {
  682         struct pt_softc *pti = pt_softc[minor(dev)];
  683         struct tty *tp = pti->pt_tty;
  684         u_char *cp = NULL;
  685         int cc = 0;
  686         u_char locbuf[BUFSIZ];
  687         int cnt = 0;
  688         int error = 0;
  689 
  690 again:
  691         mutex_spin_enter(&tty_lock);
  692         if (!ISSET(tp->t_state, TS_ISOPEN))
  693                 goto block;
  694         if (pti->pt_flags & PF_REMOTE) {
  695                 if (tp->t_canq.c_cc)
  696                         goto block;
  697                 while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
  698                         if (cc == 0) {
  699                                 cc = min(uio->uio_resid, BUFSIZ);
  700                                 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
  701                                 cp = locbuf;
  702                                 mutex_spin_exit(&tty_lock);
  703                                 error = uiomove((void *)cp, cc, uio);
  704                                 if (error)
  705                                         return (error);
  706                                 mutex_spin_enter(&tty_lock);
  707                                 /* check again for safety */
  708                                 if (!ISSET(tp->t_state, TS_ISOPEN)) {
  709                                         /*
  710                                          * adjust for data copied in but not
  711                                          * written
  712                                          */
  713                                         uio->uio_resid += cc;
  714                                         error = EIO;
  715                                         goto out;
  716                                 }
  717                         }
  718                         if (cc)
  719                                 (void) b_to_q(cp, cc, &tp->t_canq);
  720                         cc = 0;
  721                 }
  722                 (void) putc(0, &tp->t_canq);
  723                 ttwakeup(tp);
  724                 cv_broadcast(&tp->t_cancv);
  725                 error = 0;
  726                 goto out;
  727         }
  728         while (uio->uio_resid > 0) {
  729                 if (cc == 0) {
  730                         cc = min(uio->uio_resid, BUFSIZ);
  731                         cp = locbuf;
  732                         mutex_spin_exit(&tty_lock);
  733                         error = uiomove((void *)cp, cc, uio);
  734                         if (error)
  735                                 return (error);
  736                         mutex_spin_enter(&tty_lock);
  737                         /* check again for safety */
  738                         if (!ISSET(tp->t_state, TS_ISOPEN)) {
  739                                 /* adjust for data copied in but not written */
  740                                 uio->uio_resid += cc;
  741                                 error = EIO;
  742                                 goto out;
  743                         }
  744                 }
  745                 while (cc > 0) {
  746                         if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
  747                            (tp->t_canq.c_cc > 0 || !ISSET(tp->t_lflag, ICANON))) {
  748                                 cv_broadcast(&tp->t_rawcv);
  749                                 goto block;
  750                         }
  751                         /* XXX - should change l_rint to be called with lock
  752                          *       see also tty.c:ttyinput_wlock()
  753                          */
  754                         mutex_spin_exit(&tty_lock);
  755                         (*tp->t_linesw->l_rint)(*cp++, tp);
  756                         mutex_spin_enter(&tty_lock);
  757                         cnt++;
  758                         cc--;
  759                 }
  760                 cc = 0;
  761         }
  762         error = 0;
  763         goto out;
  764 
  765 block:
  766         /*
  767          * Come here to wait for slave to open, for space
  768          * in outq, or space in rawq.
  769          */
  770         if (!ISSET(tp->t_state, TS_CARR_ON)) {
  771                 /* adjust for data copied in but not written */
  772                 uio->uio_resid += cc;
  773                 error = EIO;
  774                 goto out;
  775         }
  776         if (flag & IO_NDELAY) {
  777                 /* adjust for data copied in but not written */
  778                 uio->uio_resid += cc;
  779                 error = cnt == 0 ? EWOULDBLOCK : 0;
  780                 goto out;
  781         }
  782         error = cv_wait_sig(&tp->t_rawcvf, &tty_lock);
  783         mutex_spin_exit(&tty_lock);
  784         if (error) {
  785                 /* adjust for data copied in but not written */
  786                 uio->uio_resid += cc;
  787                 return (error);
  788         }
  789         goto again;
  790 
  791 out:
  792         mutex_spin_exit(&tty_lock);
  793         return (error);
  794 }
  795 
  796 int
  797 ptcpoll(dev, events, l)
  798         dev_t dev;
  799         int events;
  800         struct lwp *l;
  801 {
  802         struct pt_softc *pti = pt_softc[minor(dev)];
  803         struct tty *tp = pti->pt_tty;
  804         int revents = 0;
  805 
  806         mutex_spin_enter(&tty_lock);
  807 
  808         if (events & (POLLIN | POLLRDNORM))
  809                 if (ISSET(tp->t_state, TS_ISOPEN) &&
  810                     ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
  811                      ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
  812                      ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
  813                         revents |= events & (POLLIN | POLLRDNORM);
  814 
  815         if (events & (POLLOUT | POLLWRNORM))
  816                 if (ISSET(tp->t_state, TS_ISOPEN) &&
  817                     ((pti->pt_flags & PF_REMOTE) ?
  818                      (tp->t_canq.c_cc == 0) :
  819                      ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
  820                       (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))))
  821                         revents |= events & (POLLOUT | POLLWRNORM);
  822 
  823         if (events & POLLHUP)
  824                 if (!ISSET(tp->t_state, TS_CARR_ON))
  825                         revents |= POLLHUP;
  826 
  827         if (revents == 0) {
  828                 if (events & (POLLIN | POLLHUP | POLLRDNORM))
  829                         selrecord(l, &pti->pt_selr);
  830 
  831                 if (events & (POLLOUT | POLLWRNORM))
  832                         selrecord(l, &pti->pt_selw);
  833         }
  834 
  835         mutex_spin_exit(&tty_lock);
  836 
  837         return (revents);
  838 }
  839 
  840 static void
  841 filt_ptcrdetach(struct knote *kn)
  842 {
  843         struct pt_softc *pti;
  844         struct tty      *tp;
  845 
  846         pti = kn->kn_hook;
  847         tp = pti->pt_tty;
  848 
  849         mutex_spin_enter(&tty_lock);
  850         SLIST_REMOVE(&pti->pt_selr.sel_klist, kn, knote, kn_selnext);
  851         mutex_spin_exit(&tty_lock);
  852 }
  853 
  854 static int
  855 filt_ptcread(struct knote *kn, long hint)
  856 {
  857         struct pt_softc *pti;
  858         struct tty      *tp;
  859         int canread;
  860 
  861         pti = kn->kn_hook;
  862         tp = pti->pt_tty;
  863 
  864         if ((hint & NOTE_SUBMIT) == 0) {
  865                 mutex_spin_enter(&tty_lock);
  866         }
  867 
  868         canread = (ISSET(tp->t_state, TS_ISOPEN) &&
  869                     ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
  870                      ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
  871                      ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)));
  872 
  873         if (canread) {
  874                 /*
  875                  * c_cc is number of characters after output post-processing;
  876                  * the amount of data actually read(2) depends on
  877                  * setting of input flags for the terminal.
  878                  */
  879                 kn->kn_data = tp->t_outq.c_cc;
  880                 if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
  881                     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
  882                         kn->kn_data++;
  883         }
  884 
  885         if ((hint & NOTE_SUBMIT) == 0) {
  886                 mutex_spin_exit(&tty_lock);
  887         }
  888 
  889         return (canread);
  890 }
  891 
  892 static void
  893 filt_ptcwdetach(struct knote *kn)
  894 {
  895         struct pt_softc *pti;
  896         struct tty      *tp;
  897 
  898         pti = kn->kn_hook;
  899         tp = pti->pt_tty;
  900 
  901         mutex_spin_enter(&tty_lock);
  902         SLIST_REMOVE(&pti->pt_selw.sel_klist, kn, knote, kn_selnext);
  903         mutex_spin_exit(&tty_lock);
  904 }
  905 
  906 static int
  907 filt_ptcwrite(struct knote *kn, long hint)
  908 {
  909         struct pt_softc *pti;
  910         struct tty      *tp;
  911         int canwrite;
  912         int nwrite;
  913 
  914         pti = kn->kn_hook;
  915         tp = pti->pt_tty;
  916 
  917         if ((hint & NOTE_SUBMIT) == 0) {
  918                 mutex_spin_enter(&tty_lock);
  919         }
  920 
  921         canwrite = (ISSET(tp->t_state, TS_ISOPEN) &&
  922                     ((pti->pt_flags & PF_REMOTE) ?
  923                      (tp->t_canq.c_cc == 0) :
  924                      ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
  925                       (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))));
  926 
  927         if (canwrite) {
  928                 if (pti->pt_flags & PF_REMOTE)
  929                         nwrite = tp->t_canq.c_cn;
  930                 else {
  931                         /* this is guaranteed to be > 0 due to above check */
  932                         nwrite = tp->t_canq.c_cn
  933                                 - (tp->t_rawq.c_cc + tp->t_canq.c_cc);
  934                 }
  935                 kn->kn_data = nwrite;
  936         }
  937 
  938         if ((hint & NOTE_SUBMIT) == 0) {
  939                 mutex_spin_exit(&tty_lock);
  940         }
  941 
  942         return (canwrite);
  943 }
  944 
  945 static const struct filterops ptcread_filtops =
  946         { 1, NULL, filt_ptcrdetach, filt_ptcread };
  947 static const struct filterops ptcwrite_filtops =
  948         { 1, NULL, filt_ptcwdetach, filt_ptcwrite };
  949 
  950 int
  951 ptckqfilter(dev_t dev, struct knote *kn)
  952 {
  953         struct pt_softc *pti = pt_softc[minor(dev)];
  954         struct klist    *klist;
  955 
  956         switch (kn->kn_filter) {
  957         case EVFILT_READ:
  958                 klist = &pti->pt_selr.sel_klist;
  959                 kn->kn_fop = &ptcread_filtops;
  960                 break;
  961         case EVFILT_WRITE:
  962                 klist = &pti->pt_selw.sel_klist;
  963                 kn->kn_fop = &ptcwrite_filtops;
  964                 break;
  965         default:
  966                 return (EINVAL);
  967         }
  968 
  969         kn->kn_hook = pti;
  970 
  971         mutex_spin_enter(&tty_lock);
  972         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  973         mutex_spin_exit(&tty_lock);
  974 
  975         return (0);
  976 }
  977 
  978 struct tty *
  979 ptytty(dev)
  980         dev_t dev;
  981 {
  982         struct pt_softc *pti = pt_softc[minor(dev)];
  983         struct tty *tp = pti->pt_tty;
  984 
  985         return (tp);
  986 }
  987 
  988 /*ARGSUSED*/
  989 int
  990 ptyioctl(dev, cmd, data, flag, l)
  991         dev_t dev;
  992         u_long cmd;
  993         void *data;
  994         int flag;
  995         struct lwp *l;
  996 {
  997         struct pt_softc *pti = pt_softc[minor(dev)];
  998         struct tty *tp = pti->pt_tty;
  999         const struct cdevsw *cdev;
 1000         u_char *cc = tp->t_cc;
 1001         int stop, error, sig;
 1002 
 1003         /*
 1004          * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
 1005          * ttywflush(tp) will hang if there are characters in the outq.
 1006          */
 1007         if (cmd == TIOCEXT) {
 1008                 /*
 1009                  * When the EXTPROC bit is being toggled, we need
 1010                  * to send an TIOCPKT_IOCTL if the packet driver
 1011                  * is turned on.
 1012                  */
 1013                 if (*(int *)data) {
 1014                         if (pti->pt_flags & PF_PKT) {
 1015                                 pti->pt_send |= TIOCPKT_IOCTL;
 1016                                 ptcwakeup(tp, FREAD);
 1017                         }
 1018                         SET(tp->t_lflag, EXTPROC);
 1019                 } else {
 1020                         if (ISSET(tp->t_lflag, EXTPROC) &&
 1021                             (pti->pt_flags & PF_PKT)) {
 1022                                 pti->pt_send |= TIOCPKT_IOCTL;
 1023                                 ptcwakeup(tp, FREAD);
 1024                         }
 1025                         CLR(tp->t_lflag, EXTPROC);
 1026                 }
 1027                 return(0);
 1028         }
 1029 
 1030 #ifndef NO_DEV_PTM
 1031         /* Allow getting the name from either the master or the slave */
 1032         if (cmd == TIOCPTSNAME)
 1033                 return pty_fill_ptmget(l, dev, -1, -1, data);
 1034 #endif
 1035 
 1036         cdev = cdevsw_lookup(dev);
 1037         if (cdev != NULL && cdev->d_open == ptcopen)
 1038                 switch (cmd) {
 1039 #ifndef NO_DEV_PTM
 1040                 case TIOCGRANTPT:
 1041                         return pty_grant_slave(l, dev);
 1042 #endif
 1043 
 1044                 case TIOCGPGRP:
 1045                         /*
 1046                          * We avoid calling ttioctl on the controller since,
 1047                          * in that case, tp must be the controlling terminal.
 1048                          */
 1049                         *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
 1050                         return (0);
 1051 
 1052                 case TIOCPKT:
 1053                         if (*(int *)data) {
 1054                                 if (pti->pt_flags & PF_UCNTL)
 1055                                         return (EINVAL);
 1056                                 pti->pt_flags |= PF_PKT;
 1057                         } else
 1058                                 pti->pt_flags &= ~PF_PKT;
 1059                         return (0);
 1060 
 1061                 case TIOCUCNTL:
 1062                         if (*(int *)data) {
 1063                                 if (pti->pt_flags & PF_PKT)
 1064                                         return (EINVAL);
 1065                                 pti->pt_flags |= PF_UCNTL;
 1066                         } else
 1067                                 pti->pt_flags &= ~PF_UCNTL;
 1068                         return (0);
 1069 
 1070                 case TIOCREMOTE:
 1071                         if (*(int *)data)
 1072                                 pti->pt_flags |= PF_REMOTE;
 1073                         else
 1074                                 pti->pt_flags &= ~PF_REMOTE;
 1075                         mutex_spin_enter(&tty_lock);
 1076                         ttyflush(tp, FREAD|FWRITE);
 1077                         mutex_spin_exit(&tty_lock);
 1078                         return (0);
 1079 
 1080 #ifdef COMPAT_OLDTTY
 1081                 case TIOCSETP:
 1082                 case TIOCSETN:
 1083 #endif
 1084                 case TIOCSETD:
 1085                 case TIOCSETA:
 1086                 case TIOCSETAW:
 1087                 case TIOCSETAF:
 1088                         mutex_spin_enter(&tty_lock);
 1089                         ndflush(&tp->t_outq, tp->t_outq.c_cc);
 1090                         mutex_spin_exit(&tty_lock);
 1091                         break;
 1092 
 1093                 case TIOCSIG:
 1094                         sig = (int)(long)*(void **)data;
 1095                         if (sig <= 0 || sig >= NSIG)
 1096                                 return (EINVAL);
 1097                         mutex_spin_enter(&tty_lock);
 1098                         if (!ISSET(tp->t_lflag, NOFLSH))
 1099                                 ttyflush(tp, FREAD|FWRITE);
 1100                         tp->t_state |= TS_SIGINFO;
 1101                         ttysig(tp, TTYSIG_PG1, sig);
 1102                         mutex_spin_exit(&tty_lock);
 1103                         return (0);
 1104 
 1105                 case FIONREAD:
 1106                         mutex_spin_enter(&tty_lock);
 1107                         *(int *)data = tp->t_outq.c_cc;
 1108                         mutex_spin_exit(&tty_lock);
 1109                         return (0);
 1110                 }
 1111 
 1112         error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
 1113         if (error == EPASSTHROUGH)
 1114                  error = ttioctl(tp, cmd, data, flag, l);
 1115         if (error == EPASSTHROUGH) {
 1116                 if (pti->pt_flags & PF_UCNTL &&
 1117                     (cmd & ~0xff) == UIOCCMD(0)) {
 1118                         if (cmd & 0xff) {
 1119                                 pti->pt_ucntl = (u_char)cmd;
 1120                                 ptcwakeup(tp, FREAD);
 1121                         }
 1122                         return (0);
 1123                 }
 1124         }
 1125         /*
 1126          * If external processing and packet mode send ioctl packet.
 1127          */
 1128         if (ISSET(tp->t_lflag, EXTPROC) && (pti->pt_flags & PF_PKT)) {
 1129                 switch(cmd) {
 1130                 case TIOCSETA:
 1131                 case TIOCSETAW:
 1132                 case TIOCSETAF:
 1133 #ifdef COMPAT_OLDTTY
 1134                 case TIOCSETP:
 1135                 case TIOCSETN:
 1136                 case TIOCSETC:
 1137                 case TIOCSLTC:
 1138                 case TIOCLBIS:
 1139                 case TIOCLBIC:
 1140                 case TIOCLSET:
 1141 #endif
 1142                         pti->pt_send |= TIOCPKT_IOCTL;
 1143                         ptcwakeup(tp, FREAD);
 1144                 default:
 1145                         break;
 1146                 }
 1147         }
 1148         stop = ISSET(tp->t_iflag, IXON) && CCEQ(cc[VSTOP], CTRL('s'))
 1149                 && CCEQ(cc[VSTART], CTRL('q'));
 1150         if (pti->pt_flags & PF_NOSTOP) {
 1151                 if (stop) {
 1152                         pti->pt_send &= ~TIOCPKT_NOSTOP;
 1153                         pti->pt_send |= TIOCPKT_DOSTOP;
 1154                         pti->pt_flags &= ~PF_NOSTOP;
 1155                         ptcwakeup(tp, FREAD);
 1156                 }
 1157         } else {
 1158                 if (!stop) {
 1159                         pti->pt_send &= ~TIOCPKT_DOSTOP;
 1160                         pti->pt_send |= TIOCPKT_NOSTOP;
 1161                         pti->pt_flags |= PF_NOSTOP;
 1162                         ptcwakeup(tp, FREAD);
 1163                 }
 1164         }
 1165         return (error);
 1166 }

Cache object: b2cee637177abeaaae5f35093a4e5aa0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.