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

Cache object: fef1568bb6cd1c0452e50d455d0479c9


[ 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.