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 /*      $OpenBSD: tty_pty.c,v 1.114 2022/09/02 07:37:57 deraadt Exp $   */
    2 /*      $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $     */
    3 
    4 /*
    5  * Copyright (c) 1982, 1986, 1989, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)tty_pty.c   8.4 (Berkeley) 2/20/95
   33  */
   34 
   35 /*
   36  * Pseudo-teletype Driver
   37  * (Actually two drivers, requiring two entries in 'cdevsw')
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/namei.h>
   43 #include <sys/mount.h>
   44 #include <sys/ioctl.h>
   45 #include <sys/proc.h>
   46 #include <sys/tty.h>
   47 #include <sys/fcntl.h>
   48 #include <sys/file.h>
   49 #include <sys/filedesc.h>
   50 #include <sys/uio.h>
   51 #include <sys/kernel.h>
   52 #include <sys/malloc.h>
   53 #include <sys/vnode.h>
   54 #include <sys/signalvar.h>
   55 #include <sys/conf.h>
   56 #include <sys/stat.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/pledge.h>
   59 #include <sys/rwlock.h>
   60 
   61 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
   62 
   63 /*
   64  * pts == /dev/tty[p-zP-T][0-9a-zA-Z]
   65  * ptc == /dev/pty[p-zP-T][0-9a-zA-Z]
   66  */
   67 
   68 /* XXX this needs to come from somewhere sane, and work with MAKEDEV */
   69 #define TTY_LETTERS "pqrstuvwxyzPQRST"
   70 #define TTY_SUFFIX "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
   71 
   72 static int pts_major;
   73 
   74 struct  pt_softc {
   75         struct  tty *pt_tty;
   76         int     pt_flags;
   77         struct  selinfo pt_selr, pt_selw;
   78         u_char  pt_send;
   79         u_char  pt_ucntl;
   80         char    pty_pn[11];
   81         char    pty_sn[11];
   82 };
   83 
   84 #define NPTY_MIN                8       /* number of initial ptys */
   85 #define NPTY_MAX                992     /* maximum number of ptys supported */
   86 
   87 static struct pt_softc **pt_softc = NULL;       /* pty array */
   88 static int npty = 0;                            /* size of pty array */
   89 static int maxptys = NPTY_MAX;                  /* maximum number of ptys */
   90 /* for pty array */
   91 struct rwlock pt_softc_lock = RWLOCK_INITIALIZER("ptarrlk");
   92 
   93 #define PF_PKT          0x08            /* packet mode */
   94 #define PF_STOPPED      0x10            /* user told stopped */
   95 #define PF_REMOTE       0x20            /* remote and flow controlled input */
   96 #define PF_NOSTOP       0x40
   97 #define PF_UCNTL        0x80            /* user control mode */
   98 
   99 void    ptyattach(int);
  100 void    ptcwakeup(struct tty *, int);
  101 struct tty *ptytty(dev_t);
  102 void    ptsstart(struct tty *);
  103 int     sysctl_pty(int *, u_int, void *, size_t *, void *, size_t);
  104 
  105 void    filt_ptcrdetach(struct knote *);
  106 int     filt_ptcread(struct knote *, long);
  107 void    filt_ptcwdetach(struct knote *);
  108 int     filt_ptcwrite(struct knote *, long);
  109 int     filt_ptcexcept(struct knote *, long);
  110 
  111 static struct pt_softc **ptyarralloc(int);
  112 static int check_pty(int);
  113 
  114 static gid_t tty_gid = TTY_GID;
  115 
  116 void    ptydevname(int, struct pt_softc *);
  117 dev_t   pty_getfree(void);
  118 
  119 void    ptmattach(int);
  120 int     ptmopen(dev_t, int, int, struct proc *);
  121 int     ptmclose(dev_t, int, int, struct proc *);
  122 int     ptmioctl(dev_t, u_long, caddr_t, int, struct proc *p);
  123 static int ptm_vn_open(struct nameidata *);
  124 
  125 void
  126 ptydevname(int minor, struct pt_softc *pti)
  127 {
  128         char buf[11] = "/dev/XtyXX";
  129         int i, j;
  130 
  131         i = minor / (sizeof(TTY_SUFFIX) - 1);
  132         j = minor % (sizeof(TTY_SUFFIX) - 1);
  133         if (i >= sizeof(TTY_LETTERS) - 1) {
  134                 pti->pty_pn[0] = '\0';
  135                 pti->pty_sn[0] = '\0';
  136                 return;
  137         }
  138         buf[5] = 'p';
  139         buf[8] = TTY_LETTERS[i];
  140         buf[9] = TTY_SUFFIX[j];
  141         memcpy(pti->pty_pn, buf, sizeof(buf));
  142         buf[5] = 't';
  143         memcpy(pti->pty_sn, buf, sizeof(buf));
  144 }
  145 
  146 /*
  147  * Allocate and zero array of nelem elements.
  148  */
  149 struct pt_softc **
  150 ptyarralloc(int nelem)
  151 {
  152         struct pt_softc **pt;
  153 
  154         pt = mallocarray(nelem, sizeof(struct pt_softc *), M_DEVBUF,
  155             M_WAITOK|M_ZERO);
  156         return pt;
  157 }
  158 
  159 /*
  160  * Check if the minor is correct and ensure necessary structures
  161  * are properly allocated.
  162  */
  163 int
  164 check_pty(int dev)
  165 {
  166         struct pt_softc *pti;
  167         int minor = minor(dev);
  168 
  169         rw_enter_write(&pt_softc_lock);
  170         if (minor >= npty) {
  171                 struct pt_softc **newpt;
  172                 int newnpty;
  173 
  174                 /* check if the requested pty can be granted */
  175                 if (minor >= maxptys)
  176                         goto limit_reached;
  177 
  178                 /* grow pty array by powers of two, up to maxptys */
  179                 for (newnpty = npty; newnpty <= minor; newnpty *= 2)
  180                         ;
  181 
  182                 if (newnpty > maxptys)
  183                         newnpty = maxptys;
  184                 newpt = ptyarralloc(newnpty);
  185 
  186                 memcpy(newpt, pt_softc, npty * sizeof(struct pt_softc *));
  187                 free(pt_softc, M_DEVBUF, npty * sizeof(struct pt_softc *));
  188                 pt_softc = newpt;
  189                 npty = newnpty;
  190         }
  191 
  192         /*
  193          * If the entry is not yet allocated, allocate one.
  194          */
  195         if (!pt_softc[minor]) {
  196                 pti = malloc(sizeof(struct pt_softc), M_DEVBUF,
  197                     M_WAITOK|M_ZERO);
  198                 pti->pt_tty = ttymalloc(1000000);
  199                 pti->pt_tty->t_dev = dev;
  200                 ptydevname(minor, pti);
  201                 pt_softc[minor] = pti;
  202         }
  203         rw_exit_write(&pt_softc_lock);
  204         return (0);
  205 limit_reached:
  206         rw_exit_write(&pt_softc_lock);
  207         tablefull("pty");
  208         return (ENXIO);
  209 }
  210 
  211 /*
  212  * Establish n (or default if n is 1) ptys in the system.
  213  */
  214 void
  215 ptyattach(int n)
  216 {
  217         /* maybe should allow 0 => none? */
  218         if (n <= 1)
  219                 n = NPTY_MIN;
  220         pt_softc = ptyarralloc(n);
  221         npty = n;
  222 
  223         /*
  224          * If we have pty, we need ptm too.
  225          */
  226         ptmattach(1);
  227 }
  228 
  229 int
  230 ptsopen(dev_t dev, int flag, int devtype, struct proc *p)
  231 {
  232         struct pt_softc *pti;
  233         struct tty *tp;
  234         int error;
  235 
  236         if ((error = check_pty(dev)))
  237                 return (error);
  238 
  239         pti = pt_softc[minor(dev)];
  240         tp = pti->pt_tty;
  241         if ((tp->t_state & TS_ISOPEN) == 0) {
  242                 tp->t_state |= TS_WOPEN;
  243                 ttychars(tp);           /* Set up default chars */
  244                 tp->t_iflag = TTYDEF_IFLAG;
  245                 tp->t_oflag = TTYDEF_OFLAG;
  246                 tp->t_lflag = TTYDEF_LFLAG;
  247                 tp->t_cflag = TTYDEF_CFLAG;
  248                 tp->t_ispeed = tp->t_ospeed = B115200;
  249                 ttsetwater(tp);         /* would be done in xxparam() */
  250         } else if (tp->t_state & TS_XCLUDE && suser(p) != 0)
  251                 return (EBUSY);
  252         if (tp->t_oproc)                        /* Ctrlr still around. */
  253                 tp->t_state |= TS_CARR_ON;
  254         while ((tp->t_state & TS_CARR_ON) == 0) {
  255                 tp->t_state |= TS_WOPEN;
  256                 if (flag & FNONBLOCK)
  257                         break;
  258                 error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, ttopen);
  259                 if (error)
  260                         return (error);
  261         }
  262         error = (*linesw[tp->t_line].l_open)(dev, tp, p);
  263         ptcwakeup(tp, FREAD|FWRITE);
  264         return (error);
  265 }
  266 
  267 int
  268 ptsclose(dev_t dev, int flag, int mode, struct proc *p)
  269 {
  270         struct pt_softc *pti = pt_softc[minor(dev)];
  271         struct tty *tp = pti->pt_tty;
  272         int error;
  273 
  274         error = (*linesw[tp->t_line].l_close)(tp, flag, p);
  275         error |= ttyclose(tp);
  276         ptcwakeup(tp, FREAD|FWRITE);
  277         return (error);
  278 }
  279 
  280 int
  281 ptsread(dev_t dev, struct uio *uio, int flag)
  282 {
  283         struct proc *p = curproc;
  284         struct process *pr = p->p_p;
  285         struct pt_softc *pti = pt_softc[minor(dev)];
  286         struct tty *tp = pti->pt_tty;
  287         int error = 0;
  288 
  289 again:
  290         if (pti->pt_flags & PF_REMOTE) {
  291                 while (isbackground(pr, tp)) {
  292                         if (sigismasked(p, SIGTTIN) ||
  293                             pr->ps_pgrp->pg_jobc == 0 ||
  294                             pr->ps_flags & PS_PPWAIT)
  295                                 return (EIO);
  296                         pgsignal(pr->ps_pgrp, SIGTTIN, 1);
  297                         error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg);
  298                         if (error)
  299                                 return (error);
  300                 }
  301                 if (tp->t_canq.c_cc == 0) {
  302                         if (flag & IO_NDELAY)
  303                                 return (EWOULDBLOCK);
  304                         error = ttysleep(tp, &tp->t_canq,
  305                             TTIPRI | PCATCH, ttyin);
  306                         if (error)
  307                                 return (error);
  308                         goto again;
  309                 }
  310                 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
  311                         if (ureadc(getc(&tp->t_canq), uio) < 0) {
  312                                 error = EFAULT;
  313                                 break;
  314                         }
  315                 if (tp->t_canq.c_cc == 1)
  316                         (void) getc(&tp->t_canq);
  317                 if (tp->t_canq.c_cc)
  318                         return (error);
  319         } else
  320                 if (tp->t_oproc)
  321                         error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
  322         ptcwakeup(tp, FWRITE);
  323         return (error);
  324 }
  325 
  326 /*
  327  * Write to pseudo-tty.
  328  * Wakeups of controlling tty will happen
  329  * indirectly, when tty driver calls ptsstart.
  330  */
  331 int
  332 ptswrite(dev_t dev, struct uio *uio, int flag)
  333 {
  334         struct pt_softc *pti = pt_softc[minor(dev)];
  335         struct tty *tp = pti->pt_tty;
  336 
  337         if (tp->t_oproc == NULL)
  338                 return (EIO);
  339         return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  340 }
  341 
  342 /*
  343  * Start output on pseudo-tty.
  344  * Wake up process polling or sleeping for input from controlling tty.
  345  */
  346 void
  347 ptsstart(struct tty *tp)
  348 {
  349         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  350 
  351         if (tp->t_state & TS_TTSTOP)
  352                 return;
  353         if (pti->pt_flags & PF_STOPPED) {
  354                 pti->pt_flags &= ~PF_STOPPED;
  355                 pti->pt_send = TIOCPKT_START;
  356         }
  357         ptcwakeup(tp, FREAD);
  358 }
  359 
  360 int
  361 ptsstop(struct tty *tp, int flush)
  362 {
  363         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  364         int flag;
  365 
  366         /* note: FLUSHREAD and FLUSHWRITE already ok */
  367         if (flush == 0) {
  368                 flush = TIOCPKT_STOP;
  369                 pti->pt_flags |= PF_STOPPED;
  370         } else
  371                 pti->pt_flags &= ~PF_STOPPED;
  372         pti->pt_send |= flush;
  373         /* change of perspective */
  374         flag = 0;
  375         if (flush & FREAD)
  376                 flag |= FWRITE;
  377         if (flush & FWRITE)
  378                 flag |= FREAD;
  379         ptcwakeup(tp, flag);
  380         return 0;
  381 }
  382 
  383 void
  384 ptcwakeup(struct tty *tp, int flag)
  385 {
  386         struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
  387 
  388         if (flag & FREAD) {
  389                 selwakeup(&pti->pt_selr);
  390                 wakeup(&tp->t_outq.c_cf);
  391         }
  392         if (flag & FWRITE) {
  393                 selwakeup(&pti->pt_selw);
  394                 wakeup(&tp->t_rawq.c_cf);
  395         }
  396 }
  397 
  398 int ptcopen(dev_t, int, int, struct proc *);
  399 
  400 int
  401 ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
  402 {
  403         struct pt_softc *pti;
  404         struct tty *tp;
  405         int error;
  406 
  407         if ((error = check_pty(dev)))
  408                 return (error);
  409 
  410         pti = pt_softc[minor(dev)];
  411         tp = pti->pt_tty;
  412         if (tp->t_oproc)
  413                 return (EIO);
  414         tp->t_oproc = ptsstart;
  415         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
  416         tp->t_lflag &= ~EXTPROC;
  417         pti->pt_flags = 0;
  418         pti->pt_send = 0;
  419         pti->pt_ucntl = 0;
  420         return (0);
  421 }
  422 
  423 int
  424 ptcclose(dev_t dev, int flag, int devtype, struct proc *p)
  425 {
  426         struct pt_softc *pti = pt_softc[minor(dev)];
  427         struct tty *tp = pti->pt_tty;
  428 
  429         (void)(*linesw[tp->t_line].l_modem)(tp, 0);
  430         tp->t_state &= ~TS_CARR_ON;
  431         tp->t_oproc = NULL;             /* mark closed */
  432         return (0);
  433 }
  434 
  435 int
  436 ptcread(dev_t dev, struct uio *uio, int flag)
  437 {
  438         struct pt_softc *pti = pt_softc[minor(dev)];
  439         struct tty *tp = pti->pt_tty;
  440         char buf[BUFSIZ];
  441         int error = 0, cc, bufcc = 0;
  442 
  443         /*
  444          * We want to block until the slave
  445          * is open, and there's something to read;
  446          * but if we lost the slave or we're NBIO,
  447          * then return the appropriate error instead.
  448          */
  449         for (;;) {
  450                 if (tp->t_state & TS_ISOPEN) {
  451                         if (pti->pt_flags & PF_PKT && pti->pt_send) {
  452                                 error = ureadc((int)pti->pt_send, uio);
  453                                 if (error)
  454                                         return (error);
  455                                 if (pti->pt_send & TIOCPKT_IOCTL) {
  456                                         cc = MIN(uio->uio_resid,
  457                                                 sizeof(tp->t_termios));
  458                                         error = uiomove(&tp->t_termios, cc, uio);
  459                                         if (error)
  460                                                 return (error);
  461                                 }
  462                                 pti->pt_send = 0;
  463                                 return (0);
  464                         }
  465                         if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
  466                                 error = ureadc((int)pti->pt_ucntl, uio);
  467                                 if (error)
  468                                         return (error);
  469                                 pti->pt_ucntl = 0;
  470                                 return (0);
  471                         }
  472                         if (tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0)
  473                                 break;
  474                 }
  475                 if ((tp->t_state & TS_CARR_ON) == 0)
  476                         return (0);     /* EOF */
  477                 if (flag & IO_NDELAY)
  478                         return (EWOULDBLOCK);
  479                 error = tsleep_nsec(&tp->t_outq.c_cf, TTIPRI | PCATCH, ttyin,
  480                     INFSLP);
  481                 if (error)
  482                         return (error);
  483         }
  484         if (pti->pt_flags & (PF_PKT|PF_UCNTL))
  485                 error = ureadc(0, uio);
  486         while (uio->uio_resid > 0 && error == 0) {
  487                 cc = MIN(uio->uio_resid, BUFSIZ);
  488                 cc = q_to_b(&tp->t_outq, buf, cc);
  489                 if (cc > bufcc)
  490                         bufcc = cc;
  491                 if (cc <= 0)
  492                         break;
  493                 error = uiomove(buf, cc, uio);
  494         }
  495         ttwakeupwr(tp);
  496         if (bufcc)
  497                 explicit_bzero(buf, bufcc);
  498         return (error);
  499 }
  500 
  501 
  502 int
  503 ptcwrite(dev_t dev, struct uio *uio, int flag)
  504 {
  505         struct pt_softc *pti = pt_softc[minor(dev)];
  506         struct tty *tp = pti->pt_tty;
  507         u_char *cp = NULL;
  508         int cc = 0, bufcc = 0;
  509         u_char buf[BUFSIZ];
  510         size_t cnt = 0;
  511         int error = 0;
  512 
  513 again:
  514         if ((tp->t_state & TS_ISOPEN) == 0)
  515                 goto block;
  516         if (pti->pt_flags & PF_REMOTE) {
  517                 if (tp->t_canq.c_cc)
  518                         goto block;
  519                 while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG(tp) - 1) {
  520                         if (cc == 0) {
  521                                 cc = MIN(uio->uio_resid, BUFSIZ);
  522                                 cc = min(cc, TTYHOG(tp) - 1 - tp->t_canq.c_cc);
  523                                 if (cc > bufcc)
  524                                         bufcc = cc;
  525                                 cp = buf;
  526                                 error = uiomove(cp, cc, uio);
  527                                 if (error)
  528                                         goto done;
  529                                 /* check again for safety */
  530                                 if ((tp->t_state & TS_ISOPEN) == 0) {
  531                                         error = EIO;
  532                                         goto done;
  533                                 }
  534                         }
  535                         if (cc)
  536                                 (void) b_to_q((char *)cp, cc, &tp->t_canq);
  537                         cc = 0;
  538                 }
  539                 (void) putc(0, &tp->t_canq);
  540                 ttwakeup(tp);
  541                 wakeup(&tp->t_canq);
  542                 goto done;
  543         }
  544         do {
  545                 if (cc == 0) {
  546                         cc = MIN(uio->uio_resid, BUFSIZ);
  547                         if (cc > bufcc)
  548                                 bufcc = cc;
  549                         cp = buf;
  550                         error = uiomove(cp, cc, uio);
  551                         if (error)
  552                                 goto done;
  553                         /* check again for safety */
  554                         if ((tp->t_state & TS_ISOPEN) == 0) {
  555                                 error = EIO;
  556                                 goto done;
  557                         }
  558                 }
  559                 bufcc = cc;
  560                 while (cc > 0) {
  561                         if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG(tp) - 2 &&
  562                            (tp->t_canq.c_cc > 0 || !ISSET(tp->t_lflag, ICANON))) {
  563                                 wakeup(&tp->t_rawq);
  564                                 goto block;
  565                         }
  566                         if ((*linesw[tp->t_line].l_rint)(*cp++, tp) == 1 &&
  567                             tsleep(tp, TTIPRI | PCATCH, "ttyretype", 1) == EINTR)
  568                                 goto interrupt;
  569                         cnt++;
  570                         cc--;
  571                 }
  572                 cc = 0;
  573         } while (uio->uio_resid > 0);
  574         goto done;
  575 block:
  576         /*
  577          * Come here to wait for slave to open, for space
  578          * in outq, or space in rawq.
  579          */
  580         if ((tp->t_state & TS_CARR_ON) == 0) {
  581                 error = EIO;
  582                 goto done;
  583         }
  584         if (flag & IO_NDELAY) {
  585                 /* adjust for data copied in but not written */
  586                 uio->uio_resid += cc;
  587                 if (cnt == 0)
  588                         error = EWOULDBLOCK;
  589                 goto done;
  590         }
  591         error = tsleep_nsec(&tp->t_rawq.c_cf, TTOPRI | PCATCH, ttyout, INFSLP);
  592         if (error == 0)
  593                 goto again;
  594 
  595 interrupt:
  596         /* adjust for data copied in but not written */
  597         uio->uio_resid += cc;
  598 done:
  599         if (bufcc)
  600                 explicit_bzero(buf, bufcc);
  601         return (error);
  602 }
  603 
  604 void
  605 filt_ptcrdetach(struct knote *kn)
  606 {
  607         struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
  608         int s;
  609 
  610         s = spltty();
  611         klist_remove_locked(&pti->pt_selr.si_note, kn);
  612         splx(s);
  613 }
  614 
  615 int
  616 filt_ptcread(struct knote *kn, long hint)
  617 {
  618         struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
  619         struct tty *tp;
  620         int active;
  621 
  622         tp = pti->pt_tty;
  623         kn->kn_data = 0;
  624 
  625         if (ISSET(tp->t_state, TS_ISOPEN)) {
  626                 if (!ISSET(tp->t_state, TS_TTSTOP))
  627                         kn->kn_data = tp->t_outq.c_cc;
  628                 if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
  629                     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
  630                         kn->kn_data++;
  631         }
  632         active = (kn->kn_data > 0);
  633 
  634         if (!ISSET(tp->t_state, TS_CARR_ON)) {
  635                 kn->kn_flags |= EV_EOF;
  636                 if (kn->kn_flags & __EV_POLL)
  637                         kn->kn_flags |= __EV_HUP;
  638                 active = 1;
  639         } else {
  640                 kn->kn_flags &= ~(EV_EOF | __EV_HUP);
  641         }
  642 
  643         return (active);
  644 }
  645 
  646 void
  647 filt_ptcwdetach(struct knote *kn)
  648 {
  649         struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
  650         int s;
  651 
  652         s = spltty();
  653         klist_remove_locked(&pti->pt_selw.si_note, kn);
  654         splx(s);
  655 }
  656 
  657 int
  658 filt_ptcwrite(struct knote *kn, long hint)
  659 {
  660         struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
  661         struct tty *tp;
  662         int active;
  663 
  664         tp = pti->pt_tty;
  665         kn->kn_data = 0;
  666 
  667         if (ISSET(tp->t_state, TS_ISOPEN)) {
  668                 if (ISSET(pti->pt_flags, PF_REMOTE)) {
  669                         if (tp->t_canq.c_cc == 0)
  670                                 kn->kn_data = tp->t_canq.c_cn;
  671                 } else if ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG(tp)-2) ||
  672                     (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))
  673                         kn->kn_data = tp->t_canq.c_cn -
  674                             (tp->t_rawq.c_cc + tp->t_canq.c_cc);
  675         }
  676         active = (kn->kn_data > 0);
  677 
  678         /* Write-side HUP condition is only for poll(2) and select(2). */
  679         if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
  680                 if (!ISSET(tp->t_state, TS_CARR_ON)) {
  681                         kn->kn_flags |= __EV_HUP;
  682                         active = 1;
  683                 } else {
  684                         kn->kn_flags &= ~__EV_HUP;
  685                 }
  686         }
  687 
  688         return (active);
  689 }
  690 
  691 int
  692 filt_ptcexcept(struct knote *kn, long hint)
  693 {
  694         struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
  695         struct tty *tp;
  696         int active = 0;
  697 
  698         tp = pti->pt_tty;
  699 
  700         if (kn->kn_sfflags & NOTE_OOB) {
  701                 /* If in packet or user control mode, check for data. */
  702                 if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
  703                     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)) {
  704                         kn->kn_fflags |= NOTE_OOB;
  705                         kn->kn_data = 1;
  706                         active = 1;
  707                 }
  708         }
  709 
  710         if (kn->kn_flags & __EV_POLL) {
  711                 if (!ISSET(tp->t_state, TS_CARR_ON)) {
  712                         kn->kn_flags |= __EV_HUP;
  713                         active = 1;
  714                 } else {
  715                         kn->kn_flags &= ~__EV_HUP;
  716                 }
  717         }
  718 
  719         return (active);
  720 }
  721 
  722 const struct filterops ptcread_filtops = {
  723         .f_flags        = FILTEROP_ISFD,
  724         .f_attach       = NULL,
  725         .f_detach       = filt_ptcrdetach,
  726         .f_event        = filt_ptcread,
  727 };
  728 
  729 const struct filterops ptcwrite_filtops = {
  730         .f_flags        = FILTEROP_ISFD,
  731         .f_attach       = NULL,
  732         .f_detach       = filt_ptcwdetach,
  733         .f_event        = filt_ptcwrite,
  734 };
  735 
  736 const struct filterops ptcexcept_filtops = {
  737         .f_flags        = FILTEROP_ISFD,
  738         .f_attach       = NULL,
  739         .f_detach       = filt_ptcrdetach,
  740         .f_event        = filt_ptcexcept,
  741 };
  742 
  743 int
  744 ptckqfilter(dev_t dev, struct knote *kn)
  745 {
  746         struct pt_softc *pti = pt_softc[minor(dev)];
  747         struct klist *klist;
  748         int s;
  749 
  750         switch (kn->kn_filter) {
  751         case EVFILT_READ:
  752                 klist = &pti->pt_selr.si_note;
  753                 kn->kn_fop = &ptcread_filtops;
  754                 break;
  755         case EVFILT_WRITE:
  756                 klist = &pti->pt_selw.si_note;
  757                 kn->kn_fop = &ptcwrite_filtops;
  758                 break;
  759         case EVFILT_EXCEPT:
  760                 klist = &pti->pt_selr.si_note;
  761                 kn->kn_fop = &ptcexcept_filtops;
  762                 break;
  763         default:
  764                 return (EINVAL);
  765         }
  766 
  767         kn->kn_hook = (caddr_t)pti;
  768 
  769         s = spltty();
  770         klist_insert_locked(klist, kn);
  771         splx(s);
  772 
  773         return (0);
  774 }
  775 
  776 struct tty *
  777 ptytty(dev_t dev)
  778 {
  779         struct pt_softc *pti = pt_softc[minor(dev)];
  780         struct tty *tp = pti->pt_tty;
  781 
  782         return (tp);
  783 }
  784 
  785 int
  786 ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  787 {
  788         struct pt_softc *pti = pt_softc[minor(dev)];
  789         struct tty *tp = pti->pt_tty;
  790         u_char *cc = tp->t_cc;
  791         int stop, error;
  792 
  793         /*
  794          * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
  795          * ttywflush(tp) will hang if there are characters in the outq.
  796          */
  797         if (cmd == TIOCEXT) {
  798                 /*
  799                  * When the EXTPROC bit is being toggled, we need
  800                  * to send an TIOCPKT_IOCTL if the packet driver
  801                  * is turned on.
  802                  */
  803                 if (*(int *)data) {
  804                         if (pti->pt_flags & PF_PKT) {
  805                                 pti->pt_send |= TIOCPKT_IOCTL;
  806                                 ptcwakeup(tp, FREAD);
  807                         }
  808                         tp->t_lflag |= EXTPROC;
  809                 } else {
  810                         if ((tp->t_lflag & EXTPROC) &&
  811                             (pti->pt_flags & PF_PKT)) {
  812                                 pti->pt_send |= TIOCPKT_IOCTL;
  813                                 ptcwakeup(tp, FREAD);
  814                         }
  815                         tp->t_lflag &= ~EXTPROC;
  816                 }
  817                 return(0);
  818         } else if (cdevsw[major(dev)].d_open == ptcopen)
  819                 switch (cmd) {
  820 
  821                 case TIOCGPGRP:
  822                         /*
  823                          * We avoid calling ttioctl on the controller since,
  824                          * in that case, tp must be the controlling terminal.
  825                          */
  826                         *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
  827                         return (0);
  828 
  829                 case TIOCPKT:
  830                         if (*(int *)data) {
  831                                 if (pti->pt_flags & PF_UCNTL)
  832                                         return (EINVAL);
  833                                 pti->pt_flags |= PF_PKT;
  834                         } else
  835                                 pti->pt_flags &= ~PF_PKT;
  836                         return (0);
  837 
  838                 case TIOCUCNTL:
  839                         if (*(int *)data) {
  840                                 if (pti->pt_flags & PF_PKT)
  841                                         return (EINVAL);
  842                                 pti->pt_flags |= PF_UCNTL;
  843                         } else
  844                                 pti->pt_flags &= ~PF_UCNTL;
  845                         return (0);
  846 
  847                 case TIOCREMOTE:
  848                         if (*(int *)data)
  849                                 pti->pt_flags |= PF_REMOTE;
  850                         else
  851                                 pti->pt_flags &= ~PF_REMOTE;
  852                         ttyflush(tp, FREAD|FWRITE);
  853                         return (0);
  854 
  855                 case TIOCSETD:
  856                 case TIOCSETA:
  857                 case TIOCSETAW:
  858                 case TIOCSETAF:
  859                         ndflush(&tp->t_outq, tp->t_outq.c_cc);
  860                         break;
  861 
  862                 case TIOCSIG:
  863                         if (*(unsigned int *)data >= NSIG ||
  864                             *(unsigned int *)data == 0)
  865                                 return(EINVAL);
  866                         if ((tp->t_lflag & NOFLSH) == 0)
  867                                 ttyflush(tp, FREAD|FWRITE);
  868                         pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
  869                         if ((*(unsigned int *)data == SIGINFO) &&
  870                             ((tp->t_lflag & NOKERNINFO) == 0))
  871                                 ttyinfo(tp);
  872                         return (0);
  873 
  874                 case FIONREAD:
  875                         /*
  876                          * FIONREAD on the master side must return the amount
  877                          * in the output queue rather than the input.
  878                          */
  879                         *(int *)data = tp->t_outq.c_cc;
  880                         return (0);
  881                 }
  882         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
  883         if (error < 0)
  884                  error = ttioctl(tp, cmd, data, flag, p);
  885         if (error < 0) {
  886                 /*
  887                  * Translate TIOCSBRK/TIOCCBRK to user mode ioctls to
  888                  * let the master interpret BREAK conditions.
  889                  */
  890                 switch (cmd) {
  891                 case TIOCSBRK:
  892                         cmd = UIOCCMD(TIOCUCNTL_SBRK);
  893                         break;
  894                 case TIOCCBRK:
  895                         cmd = UIOCCMD(TIOCUCNTL_CBRK);
  896                         break;
  897                 default:
  898                         break;
  899                 }
  900                 if (pti->pt_flags & PF_UCNTL &&
  901                     (cmd & ~0xff) == UIOCCMD(0)) {
  902                         if (cmd & 0xff) {
  903                                 pti->pt_ucntl = (u_char)cmd;
  904                                 ptcwakeup(tp, FREAD);
  905                         }
  906                         return (0);
  907                 }
  908                 error = ENOTTY;
  909         }
  910         /*
  911          * If external processing and packet mode send ioctl packet.
  912          */
  913         if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) {
  914                 switch (cmd) {
  915                 case TIOCSETA:
  916                 case TIOCSETAW:
  917                 case TIOCSETAF:
  918                         pti->pt_send |= TIOCPKT_IOCTL;
  919                         ptcwakeup(tp, FREAD);
  920                 default:
  921                         break;
  922                 }
  923         }
  924         stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) &&
  925             CCEQ(cc[VSTART], CTRL('q'));
  926         if (pti->pt_flags & PF_NOSTOP) {
  927                 if (stop) {
  928                         pti->pt_send &= ~TIOCPKT_NOSTOP;
  929                         pti->pt_send |= TIOCPKT_DOSTOP;
  930                         pti->pt_flags &= ~PF_NOSTOP;
  931                         ptcwakeup(tp, FREAD);
  932                 }
  933         } else {
  934                 if (!stop) {
  935                         pti->pt_send &= ~TIOCPKT_DOSTOP;
  936                         pti->pt_send |= TIOCPKT_NOSTOP;
  937                         pti->pt_flags |= PF_NOSTOP;
  938                         ptcwakeup(tp, FREAD);
  939                 }
  940         }
  941         return (error);
  942 }
  943 
  944 /*
  945  * Return pty-related information.
  946  */
  947 int
  948 sysctl_pty(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  949     size_t newlen)
  950 {
  951         if (namelen != 1)
  952                 return (ENOTDIR);
  953 
  954         switch (name[0]) {
  955         default:
  956                 return (EOPNOTSUPP);
  957         }
  958         /* NOTREACHED */
  959 }
  960 
  961 /*
  962  * Check if a pty is free to use.
  963  */
  964 static int
  965 pty_isfree_locked(int minor)
  966 {
  967         struct pt_softc *pt = pt_softc[minor];
  968 
  969         return (pt == NULL || pt->pt_tty == NULL ||
  970             pt->pt_tty->t_oproc == NULL);
  971 }
  972 
  973 static int
  974 pty_isfree(int minor)
  975 {
  976         int isfree;
  977 
  978         rw_enter_read(&pt_softc_lock);
  979         isfree = pty_isfree_locked(minor);
  980         rw_exit_read(&pt_softc_lock);
  981         return(isfree);
  982 }
  983 
  984 dev_t
  985 pty_getfree(void)
  986 {
  987         int i;
  988 
  989         rw_enter_read(&pt_softc_lock);
  990         for (i = 0; i < npty; i++) {
  991                 if (pty_isfree_locked(i))
  992                         break;
  993         }
  994         rw_exit_read(&pt_softc_lock);
  995         return (makedev(pts_major, i));
  996 }
  997 
  998 /*
  999  * Hacked up version of vn_open. We _only_ handle ptys and only open
 1000  * them with FREAD|FWRITE and never deal with creat or stuff like that.
 1001  *
 1002  * We need it because we have to fake up root credentials to open the pty.
 1003  */
 1004 static int
 1005 ptm_vn_open(struct nameidata *ndp)
 1006 {
 1007         struct proc *p = ndp->ni_cnd.cn_proc;
 1008         struct ucred *cred;
 1009         struct vattr vattr;
 1010         struct vnode *vp;
 1011         int error;
 1012 
 1013         if ((error = namei(ndp)) != 0)
 1014                 return (error);
 1015         vp = ndp->ni_vp;
 1016         if (vp->v_type != VCHR) {
 1017                 error = EINVAL;
 1018                 goto bad;
 1019         }
 1020 
 1021         /*
 1022          * Get us a fresh cred with root privileges.
 1023          */
 1024         cred = crget();
 1025         error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);
 1026         if (!error) {
 1027                 /* update atime/mtime */
 1028                 VATTR_NULL(&vattr);
 1029                 getnanotime(&vattr.va_atime);
 1030                 vattr.va_mtime = vattr.va_atime;
 1031                 vattr.va_vaflags |= VA_UTIMES_NULL;
 1032                 (void)VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 1033         }
 1034         crfree(cred);
 1035 
 1036         if (error)
 1037                 goto bad;
 1038 
 1039         vp->v_writecount++;
 1040 
 1041         return (0);
 1042 bad:
 1043         vput(vp);
 1044         return (error);
 1045 }
 1046 
 1047 void
 1048 ptmattach(int n)
 1049 {
 1050         /* find the major and minor of the pty devices */
 1051         int i;
 1052 
 1053         for (i = 0; i < nchrdev; i++)
 1054                 if (cdevsw[i].d_open == ptsopen)
 1055                         break;
 1056 
 1057         if (i == nchrdev)
 1058                 panic("ptmattach: Can't find pty slave in cdevsw");
 1059 
 1060         pts_major = i;
 1061 }
 1062 
 1063 int
 1064 ptmopen(dev_t dev, int flag, int mode, struct proc *p)
 1065 {
 1066         return(0);
 1067 }
 1068 
 1069 
 1070 int
 1071 ptmclose(dev_t dev, int flag, int mode, struct proc *p)
 1072 {
 1073         return (0);
 1074 }
 1075 
 1076 int
 1077 ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
 1078 {
 1079         dev_t newdev;
 1080         struct pt_softc * pti;
 1081         struct nameidata cnd, snd;
 1082         struct filedesc *fdp = p->p_fd;
 1083         struct file *cfp = NULL, *sfp = NULL;
 1084         int cindx, sindx, error;
 1085         uid_t uid;
 1086         gid_t gid;
 1087         struct vattr vattr;
 1088         struct ucred *cred;
 1089         struct ptmget *ptm = (struct ptmget *)data;
 1090 
 1091         switch (cmd) {
 1092         case PTMGET:
 1093                 fdplock(fdp);
 1094                 /* Grab two filedescriptors. */
 1095                 if ((error = falloc(p, &cfp, &cindx)) != 0) {
 1096                         fdpunlock(fdp);
 1097                         break;
 1098                 }
 1099                 if ((error = falloc(p, &sfp, &sindx)) != 0) {
 1100                         fdremove(fdp, cindx);
 1101                         fdpunlock(fdp);
 1102                         closef(cfp, p);
 1103                         break;
 1104                 }
 1105                 fdpunlock(fdp);
 1106 
 1107 retry:
 1108                 /* Find and open a free master pty. */
 1109                 newdev = pty_getfree();
 1110                 if ((error = check_pty(newdev)))
 1111                         goto bad;
 1112                 pti = pt_softc[minor(newdev)];
 1113                 NDINIT(&cnd, LOOKUP, NOFOLLOW|LOCKLEAF|KERNELPATH, UIO_SYSSPACE,
 1114                     pti->pty_pn, p);
 1115                 cnd.ni_pledge = PLEDGE_RPATH | PLEDGE_WPATH;
 1116                 if ((error = ptm_vn_open(&cnd)) != 0) {
 1117                         /*
 1118                          * Check if the master open failed because we lost
 1119                          * the race to grab it.
 1120                          */
 1121                         if (error == EIO && !pty_isfree(minor(newdev)))
 1122                                 goto retry;
 1123                         goto bad;
 1124                 }
 1125                 cfp->f_flag = FREAD|FWRITE;
 1126                 cfp->f_type = DTYPE_VNODE;
 1127                 cfp->f_ops = &vnops;
 1128                 cfp->f_data = (caddr_t) cnd.ni_vp;
 1129                 VOP_UNLOCK(cnd.ni_vp);
 1130 
 1131                 /*
 1132                  * Open the slave.
 1133                  * namei -> setattr -> unlock -> revoke -> vrele ->
 1134                  * namei -> open -> unlock
 1135                  * Three stage rocket:
 1136                  * 1. Change the owner and permissions on the slave.
 1137                  * 2. Revoke all the users of the slave.
 1138                  * 3. open the slave.
 1139                  */
 1140                 NDINIT(&snd, LOOKUP, NOFOLLOW|LOCKLEAF|KERNELPATH, UIO_SYSSPACE,
 1141                     pti->pty_sn, p);
 1142                 snd.ni_pledge = PLEDGE_RPATH | PLEDGE_WPATH;
 1143                 if ((error = namei(&snd)) != 0)
 1144                         goto bad;
 1145                 if ((snd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 1146                         gid = tty_gid;
 1147                         /* get real uid */
 1148                         uid = p->p_ucred->cr_ruid;
 1149 
 1150                         VATTR_NULL(&vattr);
 1151                         vattr.va_uid = uid;
 1152                         vattr.va_gid = gid;
 1153                         vattr.va_mode = (S_IRUSR|S_IWUSR|S_IWGRP) & ALLPERMS;
 1154                         /* Get a fake cred to pretend we're root. */
 1155                         cred = crget();
 1156                         error = VOP_SETATTR(snd.ni_vp, &vattr, cred, p);
 1157                         crfree(cred);
 1158                         if (error) {
 1159                                 vput(snd.ni_vp);
 1160                                 goto bad;
 1161                         }
 1162                 }
 1163                 VOP_UNLOCK(snd.ni_vp);
 1164                 if (snd.ni_vp->v_usecount > 1 ||
 1165                     (snd.ni_vp->v_flag & (VALIASED)))
 1166                         VOP_REVOKE(snd.ni_vp, REVOKEALL);
 1167 
 1168                 /*
 1169                  * The vnode is useless after the revoke, we need to
 1170                  * namei again.
 1171                  */
 1172                 vrele(snd.ni_vp);
 1173 
 1174                 NDINIT(&snd, LOOKUP, NOFOLLOW|LOCKLEAF|KERNELPATH, UIO_SYSSPACE,
 1175                     pti->pty_sn, p);
 1176                 snd.ni_pledge = PLEDGE_RPATH | PLEDGE_WPATH;
 1177                 /* now open it */
 1178                 if ((error = ptm_vn_open(&snd)) != 0)
 1179                         goto bad;
 1180                 sfp->f_flag = FREAD|FWRITE;
 1181                 sfp->f_type = DTYPE_VNODE;
 1182                 sfp->f_ops = &vnops;
 1183                 sfp->f_data = (caddr_t) snd.ni_vp;
 1184                 VOP_UNLOCK(snd.ni_vp);
 1185 
 1186                 /* now, put the indexen and names into struct ptmget */
 1187                 ptm->cfd = cindx;
 1188                 ptm->sfd = sindx;
 1189                 memcpy(ptm->cn, pti->pty_pn, sizeof(pti->pty_pn));
 1190                 memcpy(ptm->sn, pti->pty_sn, sizeof(pti->pty_sn));
 1191 
 1192                 /* insert files now that we've passed all errors */
 1193                 fdplock(fdp);
 1194                 fdinsert(fdp, cindx, 0, cfp);
 1195                 fdinsert(fdp, sindx, 0, sfp);
 1196                 fdpunlock(fdp);
 1197                 FRELE(cfp, p);
 1198                 FRELE(sfp, p);
 1199                 break;
 1200         default:
 1201                 error = EINVAL;
 1202                 break;
 1203         }
 1204         return (error);
 1205 bad:
 1206         fdplock(fdp);
 1207         fdremove(fdp, cindx);
 1208         fdremove(fdp, sindx);
 1209         fdpunlock(fdp);
 1210         closef(cfp, p);
 1211         closef(sfp, p);
 1212         return (error);
 1213 }

Cache object: 8333c1f658fa015739b500b02d6ebdc6


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