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_tty.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 /*-
    2  * (MPSAFE)
    3  *
    4  * Copyright (c) 1982, 1986, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)tty_tty.c   8.2 (Berkeley) 9/23/93
   32  * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $
   33  */
   34 
   35 /*
   36  * Indirect driver for controlling tty.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/conf.h>
   42 #include <sys/device.h>
   43 #include <sys/lock.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/proc.h>
   46 #include <sys/ttycom.h>
   47 #include <sys/vnode.h>
   48 #include <sys/kernel.h>
   49 #include <sys/poll.h> /* XXX: poll args used in KQ filters */
   50 #include <sys/event.h>
   51 
   52 static  d_open_t        cttyopen;
   53 static  d_close_t       cttyclose;
   54 static  d_read_t        cttyread;
   55 static  d_write_t       cttywrite;
   56 static  d_ioctl_t       cttyioctl;
   57 static  d_kqfilter_t    cttykqfilter;
   58 
   59 static void cttyfilt_detach(struct knote *);
   60 static int cttyfilt_read(struct knote *, long);
   61 static int cttyfilt_write(struct knote *, long);
   62 
   63 #define CDEV_MAJOR      1
   64 static struct dev_ops ctty_ops = {
   65         { "ctty", 0, D_TTY },
   66         .d_open =       cttyopen,
   67         .d_close =      cttyclose,
   68         .d_read =       cttyread,
   69         .d_write =      cttywrite,
   70         .d_ioctl =      cttyioctl,
   71         .d_kqfilter =   cttykqfilter
   72 };
   73 
   74 #define cttyvp(p) (((p)->p_flags & P_CONTROLT) ? \
   75                         (p)->p_session->s_ttyvp : NULL)
   76 
   77 /*
   78  * This opens /dev/tty.  Because multiple opens of /dev/tty only
   79  * generate a single open to the actual tty, the file modes are
   80  * locked to FREAD|FWRITE.
   81  */
   82 static  int
   83 cttyopen(struct dev_open_args *ap)
   84 {
   85         struct proc *p = curproc;
   86         struct vnode *ttyvp;
   87         int error;
   88 
   89         KKASSERT(p);
   90 retry:
   91         if ((ttyvp = cttyvp(p)) == NULL)
   92                 return (ENXIO);
   93         if (ttyvp->v_flag & VCTTYISOPEN)
   94                 return (0);
   95 
   96         /*
   97          * Messy interlock, don't let the vnode go away while we try to
   98          * lock it and check for race after we might have blocked.
   99          *
  100          * WARNING! The device open (devfs_spec_open()) temporarily
  101          *          releases the vnode lock on ttyvp when issuing the
  102          *          dev_dopen(), which means that the VCTTYISOPEn flag
  103          *          can race during the VOP_OPEN().
  104          *
  105          *          If something does race we have to undo our potentially
  106          *          extra open.
  107          */
  108         vhold(ttyvp);
  109         vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
  110         if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
  111                 kprintf("Warning: cttyopen: race-1 avoided\n");
  112                 vn_unlock(ttyvp);
  113                 vdrop(ttyvp);
  114                 goto retry;
  115         }
  116         error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
  117         if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
  118                 kprintf("Warning: cttyopen: race-2 avoided\n");
  119                 if (error == 0)
  120                         VOP_CLOSE(ttyvp, FREAD|FWRITE);
  121                 vn_unlock(ttyvp);
  122                 vdrop(ttyvp);
  123                 goto retry;
  124         }
  125         if (error == 0)
  126                 vsetflags(ttyvp, VCTTYISOPEN);
  127         vn_unlock(ttyvp);
  128         vdrop(ttyvp);
  129         return(error);
  130 }
  131 
  132 /*
  133  * This closes /dev/tty.  Because multiple opens of /dev/tty only
  134  * generate a single open to the actual tty, the file modes are
  135  * locked to FREAD|FWRITE.
  136  */
  137 static int
  138 cttyclose(struct dev_close_args *ap)
  139 {
  140         struct proc *p = curproc;
  141         struct vnode *ttyvp;
  142         int error;
  143 
  144         KKASSERT(p);
  145 retry:
  146         /*
  147          * The tty may have been TIOCNOTTY'd, don't return an
  148          * error on close.  We just have nothing to do.
  149          */
  150         if ((ttyvp = cttyvp(p)) == NULL)
  151                 return(0);
  152         if (ttyvp->v_flag & VCTTYISOPEN) {
  153                 /*
  154                  * Avoid a nasty race if we block while getting the lock.
  155                  */
  156                 vref(ttyvp);
  157                 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY |
  158                                        LK_FAILRECLAIM);
  159                 if (error) {
  160                         vrele(ttyvp);
  161                         goto retry;
  162                 }
  163                 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) {
  164                         kprintf("Warning: cttyclose: race avoided\n");
  165                         vn_unlock(ttyvp);
  166                         vrele(ttyvp);
  167                         goto retry;
  168                 }
  169                 vclrflags(ttyvp, VCTTYISOPEN);
  170                 error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
  171                 vn_unlock(ttyvp);
  172                 vrele(ttyvp);
  173         } else {
  174                 error = 0;
  175         }
  176         return(error);
  177 }
  178 
  179 /*
  180  * Read from the controlling terminal (/dev/tty).  The tty is refed as
  181  * of the cttyvp(), but the ref can get ripped out from under us if
  182  * the controlling terminal is revoked while we are blocked on the lock,
  183  * so use vget() instead of vn_lock().
  184  */
  185 static  int
  186 cttyread(struct dev_read_args *ap)
  187 {
  188         struct proc *p = curproc;
  189         struct vnode *ttyvp;
  190         int error;
  191 
  192         KKASSERT(p);
  193         ttyvp = cttyvp(p);
  194         if (ttyvp == NULL)
  195                 return (EIO);
  196         if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
  197                 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
  198                 vput(ttyvp);
  199         }
  200         return (error);
  201 }
  202 
  203 /*
  204  * Read from the controlling terminal (/dev/tty).  The tty is refed as
  205  * of the cttyvp(), but the ref can get ripped out from under us if
  206  * the controlling terminal is revoked while we are blocked on the lock,
  207  * so use vget() instead of vn_lock().
  208  */
  209 static  int
  210 cttywrite(struct dev_write_args *ap)
  211 {
  212         struct proc *p = curproc;
  213         struct vnode *ttyvp;
  214         int error;
  215 
  216         KKASSERT(p);
  217         ttyvp = cttyvp(p);
  218         if (ttyvp == NULL)
  219                 return (EIO);
  220         if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
  221                 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
  222                 vput(ttyvp);
  223         }
  224         return (error);
  225 }
  226 
  227 /*ARGSUSED*/
  228 static  int
  229 cttyioctl(struct dev_ioctl_args *ap)
  230 {
  231         struct vnode *ttyvp;
  232         struct proc *p = curproc;
  233 
  234         KKASSERT(p);
  235         lwkt_gettoken(&p->p_token);
  236         ttyvp = cttyvp(p);
  237         if (ttyvp == NULL) {
  238                 lwkt_reltoken(&p->p_token);
  239                 return (EIO);
  240         }
  241         /*
  242          * Don't allow controlling tty to be set to the controlling tty
  243          * (infinite recursion).
  244          */
  245         if (ap->a_cmd == TIOCSCTTY) {
  246                 lwkt_reltoken(&p->p_token);
  247                 return EINVAL;
  248         }
  249         if (ap->a_cmd == TIOCNOTTY) {
  250                 if (!SESS_LEADER(p)) {
  251                         p->p_flags &= ~P_CONTROLT;
  252                         lwkt_reltoken(&p->p_token);
  253                         return (0);
  254                 } else {
  255                         lwkt_reltoken(&p->p_token);
  256                         return (EINVAL);
  257                 }
  258         }
  259         lwkt_reltoken(&p->p_token);
  260 
  261         return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag,
  262                           ap->a_cred, ap->a_sysmsg));
  263 }
  264 
  265 static struct filterops cttyfiltops_read =
  266         { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_read };
  267 static struct filterops cttyfiltops_write =
  268         { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_write };
  269 
  270 static int
  271 cttykqfilter(struct dev_kqfilter_args *ap)
  272 {
  273         cdev_t dev = ap->a_head.a_dev;
  274         struct proc *p = curproc;
  275         struct knote *kn = ap->a_kn;
  276         struct vnode *ttyvp;
  277 
  278         KKASSERT(p);
  279         ttyvp = cttyvp(p);
  280 
  281         if (ttyvp != NULL)
  282                 return (VOP_KQFILTER(ttyvp, kn));
  283 
  284         ap->a_result = 0;
  285 
  286         switch (kn->kn_filter) {
  287         case EVFILT_READ:
  288                 kn->kn_fop = &cttyfiltops_read;
  289                 kn->kn_hook = (caddr_t)dev;
  290                 break;
  291         case EVFILT_WRITE:
  292                 kn->kn_fop = &cttyfiltops_write;
  293                 kn->kn_hook = (caddr_t)dev;
  294                 break;
  295         default:
  296                 ap->a_result = EOPNOTSUPP;
  297                 return (0);
  298         }
  299 
  300         return (0);
  301 }
  302 
  303 static void
  304 cttyfilt_detach(struct knote *kn) {}
  305 
  306 static int
  307 cttyfilt_read(struct knote *kn, long hint)
  308 {
  309         cdev_t dev = (cdev_t)kn->kn_hook;
  310 
  311         if (seltrue(dev, POLLIN | POLLRDNORM))
  312                 return (1);
  313 
  314         return (0);
  315 }
  316 
  317 static int
  318 cttyfilt_write(struct knote *kn, long hint)
  319 {
  320         cdev_t dev = (cdev_t)kn->kn_hook;
  321 
  322         if (seltrue(dev, POLLOUT | POLLWRNORM))
  323                 return (1);
  324 
  325         return (0);
  326 }
  327 
  328 static void
  329 ctty_drvinit(void *unused __unused)
  330 {
  331         make_dev(&ctty_ops, 0, 0, 0, 0666, "tty");
  332 }
  333 
  334 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)

Cache object: ed769a37dee4ad78099f87f1b1cc11df


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