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_ptm.c

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

    1 /*      $NetBSD: tty_ptm.c,v 1.15 2006/11/01 10:17:59 yamt Exp $        */
    2 
    3 /*-
    4  * Copyright (c) 2004 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *        This product includes software developed by the NetBSD
   18  *        Foundation, Inc. and its contributors.
   19  * 4. Neither the name of The NetBSD Foundation nor the names of its
   20  *    contributors may be used to endorse or promote products derived
   21  *    from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: tty_ptm.c,v 1.15 2006/11/01 10:17:59 yamt Exp $");
   38 
   39 #include "opt_ptm.h"
   40 
   41 /* pty multiplexor driver /dev/ptm{,x} */
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/ioctl.h>
   46 #include <sys/proc.h>
   47 #include <sys/tty.h>
   48 #include <sys/stat.h>
   49 #include <sys/file.h>
   50 #include <sys/uio.h>
   51 #include <sys/kernel.h>
   52 #include <sys/vnode.h>
   53 #include <sys/namei.h>
   54 #include <sys/signalvar.h>
   55 #include <sys/uio.h>
   56 #include <sys/filedesc.h>
   57 #include <sys/conf.h>
   58 #include <sys/poll.h>
   59 #include <sys/malloc.h>
   60 #include <sys/pty.h>
   61 #include <sys/kauth.h>
   62 
   63 #ifdef DEBUG_PTM
   64 #define DPRINTF(a)      printf a
   65 #else
   66 #define DPRINTF(a)
   67 #endif
   68 
   69 #ifdef NO_DEV_PTM
   70 const struct cdevsw ptm_cdevsw = {
   71         noopen, noclose, noread, nowrite, noioctl,
   72         nostop, notty, nopoll, nommap, nokqfilter, D_TTY
   73 };
   74 #else
   75 
   76 static struct ptm_pty *ptm;
   77 int pts_major, ptc_major;
   78 
   79 static dev_t pty_getfree(void);
   80 static int pty_alloc_master(struct lwp *, int *, dev_t *);
   81 static int pty_alloc_slave(struct lwp *, int *, dev_t);
   82 
   83 void ptmattach(int);
   84 
   85 dev_t
   86 pty_makedev(char ms, int minor)
   87 {
   88         return makedev(ms == 't' ? pts_major : ptc_major, minor);
   89 }
   90 
   91 
   92 static dev_t
   93 pty_getfree(void)
   94 {
   95         extern struct simplelock pt_softc_mutex;
   96         int i;
   97 
   98         simple_lock(&pt_softc_mutex);
   99         for (i = 0; i < npty; i++) {
  100                 if (pty_isfree(i, 0))
  101                         break;
  102         }
  103         simple_unlock(&pt_softc_mutex);
  104         return pty_makedev('t', i);
  105 }
  106 
  107 /*
  108  * Hacked up version of vn_open. We _only_ handle ptys and only open
  109  * them with FREAD|FWRITE and never deal with creat or stuff like that.
  110  *
  111  * We need it because we have to fake up root credentials to open the pty.
  112  */
  113 int
  114 pty_vn_open(struct vnode *vp, struct lwp *l)
  115 {
  116         int error;
  117 
  118         if (vp->v_type != VCHR) {
  119                 vput(vp);
  120                 return EINVAL;
  121         }
  122 
  123         error = VOP_OPEN(vp, FREAD|FWRITE, lwp0.l_cred, l);
  124 
  125         if (error) {
  126                 vput(vp);
  127                 return error;
  128         }
  129 
  130         vp->v_writecount++;
  131 
  132         return 0;
  133 }
  134 
  135 static int
  136 pty_alloc_master(struct lwp *l, int *fd, dev_t *dev)
  137 {
  138         int error;
  139         struct file *fp;
  140         struct vnode *vp;
  141         int md;
  142 
  143         if ((error = falloc(l, &fp, fd)) != 0) {
  144                 DPRINTF(("falloc %d\n", error));
  145                 return error;
  146         }
  147 retry:
  148         /* Find and open a free master pty. */
  149         *dev = pty_getfree();
  150         md = minor(*dev);
  151         if ((error = pty_check(md)) != 0) {
  152                 DPRINTF(("pty_check %d\n", error));
  153                 goto bad;
  154         }
  155         if (ptm == NULL) {
  156                 DPRINTF(("no ptm\n"));
  157                 error = EOPNOTSUPP;
  158                 goto bad;
  159         }
  160         if ((error = (*ptm->allocvp)(ptm, l, &vp, *dev, 'p')) != 0) {
  161                 DPRINTF(("pty_allocvp %d\n", error));
  162                 goto bad;
  163         }
  164 
  165         if ((error = pty_vn_open(vp, l)) != 0) {
  166                 DPRINTF(("pty_vn_open %d\n", error));
  167                 /*
  168                  * Check if the master open failed because we lost
  169                  * the race to grab it.
  170                  */
  171                 if (error != EIO)
  172                         goto bad;
  173                 error = !pty_isfree(md, 1);
  174                 DPRINTF(("pty_isfree %d\n", error));
  175                 if (error)
  176                         goto retry;
  177                 else
  178                         goto bad;
  179         }
  180         fp->f_flag = FREAD|FWRITE;
  181         fp->f_type = DTYPE_VNODE;
  182         fp->f_ops = &vnops;
  183         fp->f_data = vp;
  184         VOP_UNLOCK(vp, 0);
  185         FILE_SET_MATURE(fp);
  186         FILE_UNUSE(fp, l);
  187         return 0;
  188 bad:
  189         FILE_UNUSE(fp, l);
  190         fdremove(l->l_proc->p_fd, *fd);
  191         ffree(fp);
  192         return error;
  193 }
  194 
  195 int
  196 pty_grant_slave(struct lwp *l, dev_t dev)
  197 {
  198         int error;
  199         struct vnode *vp;
  200 
  201         /*
  202          * Open the slave.
  203          * namei -> setattr -> unlock -> revoke -> vrele ->
  204          * namei -> open -> unlock
  205          * Three stage rocket:
  206          * 1. Change the owner and permissions on the slave.
  207          * 2. Revoke all the users of the slave.
  208          * 3. open the slave.
  209          */
  210         if (ptm == NULL)
  211                 return EOPNOTSUPP;
  212         if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
  213                 return error;
  214 
  215         if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
  216                 struct vattr vattr;
  217                 (*ptm->getvattr)(ptm, l, &vattr);
  218                 /* Do the VOP_SETATTR() as root. */
  219                 error = VOP_SETATTR(vp, &vattr, lwp0.l_cred, l);
  220                 if (error) {
  221                         DPRINTF(("setattr %d\n", error));
  222                         VOP_UNLOCK(vp, 0);
  223                         vrele(vp);
  224                         return error;
  225                 }
  226         }
  227         VOP_UNLOCK(vp, 0);
  228         if (vp->v_usecount > 1 ||
  229             (vp->v_flag & (VALIASED | VLAYER)))
  230                 VOP_REVOKE(vp, REVOKEALL);
  231 
  232         /*
  233          * The vnode is useless after the revoke, we need to get it again.
  234          */
  235         vrele(vp);
  236         return 0;
  237 }
  238 
  239 static int
  240 pty_alloc_slave(struct lwp *l, int *fd, dev_t dev)
  241 {
  242         int error;
  243         struct file *fp;
  244         struct vnode *vp;
  245 
  246         /* Grab a filedescriptor for the slave */
  247         if ((error = falloc(l, &fp, fd)) != 0) {
  248                 DPRINTF(("falloc %d\n", error));
  249                 return error;
  250         }
  251 
  252         if (ptm == NULL) {
  253                 error = EOPNOTSUPP;
  254                 goto bad;
  255         }
  256 
  257         if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
  258                 goto bad;
  259         if ((error = pty_vn_open(vp, l)) != 0)
  260                 goto bad;
  261 
  262         fp->f_flag = FREAD|FWRITE;
  263         fp->f_type = DTYPE_VNODE;
  264         fp->f_ops = &vnops;
  265         fp->f_data = vp;
  266         VOP_UNLOCK(vp, 0);
  267         FILE_SET_MATURE(fp);
  268         FILE_UNUSE(fp, l);
  269         return 0;
  270 bad:
  271         FILE_UNUSE(fp, l);
  272         fdremove(l->l_proc->p_fd, *fd);
  273         ffree(fp);
  274         return error;
  275 }
  276 
  277 struct ptm_pty *
  278 pty_sethandler(struct ptm_pty *nptm)
  279 {
  280         struct ptm_pty *optm = ptm;
  281         ptm = nptm;
  282         return optm;
  283 }
  284 
  285 int
  286 pty_fill_ptmget(struct lwp *l, dev_t dev, int cfd, int sfd, void *data)
  287 {
  288         struct ptmget *ptmg = data;
  289         int error;
  290 
  291         if (ptm == NULL)
  292                 return EOPNOTSUPP;
  293 
  294         ptmg->cfd = cfd == -1 ? minor(dev) : cfd;
  295         ptmg->sfd = sfd == -1 ? minor(dev) : sfd;
  296 
  297         error = (*ptm->makename)(ptm, l, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
  298         if (error)
  299                 return error;
  300 
  301         return (*ptm->makename)(ptm, l, ptmg->sn, sizeof(ptmg->sn), dev, 't');
  302 }
  303 
  304 void
  305 /*ARGSUSED*/
  306 ptmattach(int n)
  307 {
  308         extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
  309         /* find the major and minor of the pty devices */
  310         if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
  311                 panic("ptmattach: Can't find pty slave in cdevsw");
  312         if ((ptc_major = cdevsw_lookup_major(&ptc_cdevsw)) == -1)
  313                 panic("ptmattach: Can't find pty master in cdevsw");
  314 #ifdef COMPAT_BSDPTY
  315         ptm = &ptm_bsdpty;
  316 #endif
  317 }
  318 
  319 static int
  320 /*ARGSUSED*/
  321 ptmopen(dev_t dev, int flag, int mode, struct lwp *l)
  322 {
  323         int error;
  324         int fd;
  325         dev_t ttydev;
  326 
  327         switch(minor(dev)) {
  328         case 0:         /* /dev/ptmx */
  329         case 2:         /* /emul/linux/dev/ptmx */
  330                 if ((error = pty_alloc_master(l, &fd, &ttydev)) != 0)
  331                         return error;
  332                 if (minor(dev) == 2) {
  333                         /*
  334                          * Linux ptyfs grants the pty right here.
  335                          * Handle this case here, instead of writing
  336                          * a new linux module.
  337                          */
  338                         if ((error = pty_grant_slave(l, ttydev)) != 0) {
  339                                 struct file *fp =
  340                                     fd_getfile(l->l_proc->p_fd, fd);
  341                                 FILE_UNUSE(fp, l);
  342                                 fdremove(l->l_proc->p_fd, fd);
  343                                 ffree(fp);
  344                                 return error;
  345                         }
  346                 }
  347                 curlwp->l_dupfd = fd;
  348                 return EMOVEFD;
  349         case 1:         /* /dev/ptm */
  350                 return 0;
  351         default:
  352                 return ENODEV;
  353         }
  354 }
  355 
  356 static int
  357 /*ARGSUSED*/
  358 ptmclose(dev_t dev, int flag, int mode, struct lwp *l)
  359 {
  360 
  361         return (0);
  362 }
  363 
  364 static int
  365 /*ARGSUSED*/
  366 ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
  367 {
  368         int error;
  369         dev_t newdev;
  370         int cfd, sfd;
  371         struct file *fp;
  372         struct proc *p = l->l_proc;
  373 
  374         error = 0;
  375         switch (cmd) {
  376         case TIOCPTMGET:
  377                 if ((error = pty_alloc_master(l, &cfd, &newdev)) != 0)
  378                         return error;
  379 
  380                 if ((error = pty_grant_slave(l, newdev)) != 0)
  381                         goto bad;
  382 
  383                 if ((error = pty_alloc_slave(l, &sfd, newdev)) != 0)
  384                         goto bad;
  385 
  386                 /* now, put the indices and names into struct ptmget */
  387                 return pty_fill_ptmget(l, newdev, cfd, sfd, data);
  388         default:
  389                 DPRINTF(("ptmioctl EINVAL\n"));
  390                 return EINVAL;
  391         }
  392 bad:
  393         fp = fd_getfile(p->p_fd, cfd);
  394         FILE_UNUSE(fp, l);
  395         fdremove(p->p_fd, cfd);
  396         ffree(fp);
  397         return error;
  398 }
  399 
  400 const struct cdevsw ptm_cdevsw = {
  401         ptmopen, ptmclose, noread, nowrite, ptmioctl,
  402         nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
  403 };
  404 #endif

Cache object: c9f8350213b82c486e1e3531ed69ff15


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