LCOV - code coverage report
Current view: top level - kern - tty_pty.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 597 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13