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.4 2004/11/30 04:25:44 christos 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.4 2004/11/30 04:25:44 christos 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 
   62 #ifdef DEBUG_PTM
   63 #define DPRINTF(a)      printf a
   64 #else
   65 #define DPRINTF(a)
   66 #endif
   67 
   68 #ifdef NO_DEV_PTM
   69 const struct cdevsw ptm_cdevsw = {
   70         noopen, noclose, noread, nowrite, noioctl,
   71         nostop, notty, nopoll, nommap, nokqfilter, D_TTY
   72 };
   73 #else
   74 
   75 static struct ptm_pty *ptm;
   76 int pts_major, ptc_major;
   77 
   78 static dev_t pty_getfree(void);
   79 static int pty_alloc_master(struct proc *, int *, dev_t *);
   80 static int pty_alloc_slave(struct proc *, int *, dev_t);
   81 
   82 void ptmattach(int);
   83 
   84 dev_type_open(ptmopen);
   85 dev_type_close(ptmclose);
   86 dev_type_ioctl(ptmioctl);
   87 
   88 const struct cdevsw ptm_cdevsw = {
   89         ptmopen, ptmclose, noread, nowrite, ptmioctl,
   90         nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
   91 };
   92 
   93 dev_t
   94 pty_makedev(char ms, int minor)
   95 {
   96         return makedev(ms == 't' ? pts_major : ptc_major, minor);
   97 }
   98 
   99 static dev_t
  100 pty_getfree(void)
  101 {
  102         extern struct simplelock pt_softc_mutex;
  103         int i;
  104 
  105         simple_lock(&pt_softc_mutex);
  106         for (i = 0; i < npty; i++) {
  107                 if (pty_isfree(i, 0))
  108                         break;
  109         }
  110         simple_unlock(&pt_softc_mutex);
  111         return pty_makedev('t', i);
  112 }
  113 
  114 /*
  115  * Hacked up version of vn_open. We _only_ handle ptys and only open
  116  * them with FREAD|FWRITE and never deal with creat or stuff like that.
  117  *
  118  * We need it because we have to fake up root credentials to open the pty.
  119  */
  120 int
  121 pty_vn_open(struct vnode *vp, struct proc *p)
  122 {
  123         struct ucred *cred;
  124         int error;
  125 
  126         if (vp->v_type != VCHR) {
  127                 vput(vp);
  128                 return EINVAL;
  129         }
  130 
  131         /*
  132          * Get us a fresh cred with root privileges.
  133          */
  134         cred = crget();
  135         error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);
  136         crfree(cred);
  137 
  138         if (error) {
  139                 vput(vp);
  140                 return error;
  141         }
  142 
  143         vp->v_writecount++;
  144 
  145         return 0;
  146 }
  147 
  148 static int
  149 pty_alloc_master(struct proc *p, int *fd, dev_t *dev)
  150 {
  151         int error;
  152         struct file *fp;
  153         struct vnode *vp;
  154         int md;
  155 
  156         if ((error = falloc(p, &fp, fd)) != 0) {
  157                 DPRINTF(("falloc %d\n", error));
  158                 return error;
  159         }
  160 retry:
  161         /* Find and open a free master pty. */
  162         *dev = pty_getfree();
  163         md = minor(*dev);
  164         if ((error = pty_check(md)) != 0) {
  165                 DPRINTF(("pty_check %d\n", error));
  166                 goto bad;
  167         }
  168         if (ptm == NULL) {
  169                 error = EOPNOTSUPP;
  170                 goto bad;
  171         }
  172         if ((error = (*ptm->allocvp)(ptm, p, &vp, *dev, 'p')) != 0)
  173                 goto bad;
  174 
  175         if ((error = pty_vn_open(vp, p)) != 0) {
  176                 /*
  177                  * Check if the master open failed because we lost
  178                  * the race to grab it.
  179                  */
  180                 if (error != EIO)
  181                         goto bad;
  182                 error = !pty_isfree(md, 1);
  183                 if (error)
  184                         goto retry;
  185                 else
  186                         goto bad;
  187         }
  188         fp->f_flag = FREAD|FWRITE;
  189         fp->f_type = DTYPE_VNODE;
  190         fp->f_ops = &vnops;
  191         fp->f_data = vp;
  192         VOP_UNLOCK(vp, 0);
  193         FILE_SET_MATURE(fp);
  194         FILE_UNUSE(fp, p);
  195         return 0;
  196 bad:
  197         FILE_UNUSE(fp, p);
  198         fdremove(p->p_fd, *fd);
  199         ffree(fp);
  200         return error;
  201 }
  202 
  203 int
  204 pty_grant_slave(struct proc *p, dev_t dev)
  205 {
  206         int error;
  207         struct vnode *vp;
  208 
  209         /*
  210          * Open the slave.
  211          * namei -> setattr -> unlock -> revoke -> vrele ->
  212          * namei -> open -> unlock
  213          * Three stage rocket:
  214          * 1. Change the owner and permissions on the slave.
  215          * 2. Revoke all the users of the slave.
  216          * 3. open the slave.
  217          */
  218         if (ptm == NULL)
  219                 return EOPNOTSUPP;
  220 
  221         if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)
  222                 return error;
  223 
  224         if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
  225                 struct vattr vattr;
  226                 struct ucred *cred;
  227                 (*ptm->getvattr)(ptm, p, &vattr);
  228                 /* Get a fake cred to pretend we're root. */
  229                 cred = crget();
  230                 error = VOP_SETATTR(vp, &vattr, cred, p);
  231                 crfree(cred);
  232                 if (error) {
  233                         DPRINTF(("setattr %d\n", error));
  234                         VOP_UNLOCK(vp, 0);
  235                         vrele(vp);
  236                         return error;
  237                 }
  238         }
  239         VOP_UNLOCK(vp, 0);
  240         if (vp->v_usecount > 1 ||
  241             (vp->v_flag & (VALIASED | VLAYER)))
  242                 VOP_REVOKE(vp, REVOKEALL);
  243 
  244         /*
  245          * The vnode is useless after the revoke, we need to get it again.
  246          */
  247         vrele(vp);
  248         return 0;
  249 }
  250 
  251 static int
  252 pty_alloc_slave(struct proc *p, int *fd, dev_t dev)
  253 {
  254         int error;
  255         struct file *fp;
  256         struct vnode *vp;
  257 
  258         /* Grab a filedescriptor for the slave */
  259         if ((error = falloc(p, &fp, fd)) != 0) {
  260                 DPRINTF(("falloc %d\n", error));
  261                 return error;
  262         }
  263 
  264         if (ptm == NULL) {
  265                 error = EOPNOTSUPP;
  266                 goto bad;
  267         }
  268 
  269         if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)
  270                 goto bad;
  271         if ((error = pty_vn_open(vp, p)) != 0)
  272                 goto bad;
  273 
  274         fp->f_flag = FREAD|FWRITE;
  275         fp->f_type = DTYPE_VNODE;
  276         fp->f_ops = &vnops;
  277         fp->f_data = vp;
  278         VOP_UNLOCK(vp, 0);
  279         FILE_SET_MATURE(fp);
  280         FILE_UNUSE(fp, p);
  281         return 0;
  282 bad:
  283         FILE_UNUSE(fp, p);
  284         fdremove(p->p_fd, *fd);
  285         ffree(fp);
  286         return error;
  287 }
  288 
  289 struct ptm_pty *
  290 pty_sethandler(struct ptm_pty *nptm)
  291 {
  292         struct ptm_pty *optm = ptm;
  293         ptm = nptm;
  294         return optm;
  295 }
  296 
  297 int
  298 pty_fill_ptmget(dev_t dev, int cfd, int sfd, void *data)
  299 {
  300         struct ptmget *ptmg = data;
  301         int error;
  302 
  303         if (ptm == NULL)
  304                 return EOPNOTSUPP;
  305 
  306         ptmg->cfd = cfd == -1 ? minor(dev) : cfd;
  307         ptmg->sfd = sfd == -1 ? minor(dev) : sfd;
  308 
  309         error = (*ptm->makename)(ptm, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
  310         if (error)
  311                 return error;
  312 
  313         return (*ptm->makename)(ptm, ptmg->sn, sizeof(ptmg->sn), dev, 't');
  314 }
  315 
  316 void
  317 /*ARGSUSED*/
  318 ptmattach(int n)
  319 {
  320         extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
  321         /* find the major and minor of the pty devices */
  322         if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
  323                 panic("ptmattach: Can't find pty slave in cdevsw");
  324         if ((ptc_major = cdevsw_lookup_major(&ptc_cdevsw)) == -1)
  325                 panic("ptmattach: Can't find pty master in cdevsw");
  326 #ifdef COMPAT_BSDPTY
  327         ptm = &ptm_bsdpty;
  328 #endif
  329 }
  330 
  331 int
  332 /*ARGSUSED*/
  333 ptmopen(dev_t dev, int flag, int mode, struct proc *p)
  334 {
  335         int error;
  336         int fd;
  337 
  338         switch(minor(dev)) {
  339         case 0:         /* /dev/ptmx */
  340                 if ((error = pty_alloc_master(p, &fd, &dev)) != 0)
  341                         return error;
  342                 curlwp->l_dupfd = fd;
  343                 return EMOVEFD;
  344         case 1:         /* /dev/ptm */
  345                 return 0;
  346         default:
  347                 return ENODEV;
  348         }
  349 }
  350 
  351 int
  352 /*ARGSUSED*/
  353 ptmclose(dev_t dev, int flag, int mode, struct proc *p)
  354 {
  355         return (0);
  356 }
  357 
  358 int
  359 /*ARGSUSED*/
  360 ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  361 {
  362         int error;
  363         dev_t newdev;
  364         int cfd, sfd;
  365         struct file *fp;
  366 
  367         error = 0;
  368         switch (cmd) {
  369         case TIOCPTMGET:
  370                 if ((error = pty_alloc_master(p, &cfd, &newdev)) != 0)
  371                         return error;
  372 
  373                 if ((error = pty_grant_slave(p, newdev)) != 0)
  374                         goto bad;
  375 
  376                 if ((error = pty_alloc_slave(p, &sfd, newdev)) != 0)
  377                         goto bad;
  378 
  379                 /* now, put the indices and names into struct ptmget */
  380                 return pty_fill_ptmget(newdev, cfd, sfd, data);
  381         default:
  382                 DPRINTF(("ptmioctl EINVAL\n"));
  383                 return EINVAL;
  384         }
  385 bad:
  386         fp = fd_getfile(p->p_fd, cfd);
  387         fdremove(p->p_fd, cfd);
  388         ffree(fp);
  389         return error;
  390 }
  391 #endif

Cache object: f27017ac1fa2ac3a0d90bdcc930f71d1


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