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/miscfs/fdesc/fdesc_vnops.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: fdesc_vnops.c,v 1.83 2005/02/26 22:59:00 perry Exp $   */
    2 
    3 /*
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software donated to Berkeley by
    8  * Jan-Simon Pendry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)fdesc_vnops.c       8.17 (Berkeley) 5/22/95
   35  *
   36  * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp #
   37  */
   38 
   39 /*
   40  * /dev/fd Filesystem
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.c,v 1.83 2005/02/26 22:59:00 perry Exp $");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/time.h>
   49 #include <sys/proc.h>
   50 #include <sys/kernel.h> /* boottime */
   51 #include <sys/resourcevar.h>
   52 #include <sys/socketvar.h>
   53 #include <sys/filedesc.h>
   54 #include <sys/vnode.h>
   55 #include <sys/malloc.h>
   56 #include <sys/conf.h>
   57 #include <sys/file.h>
   58 #include <sys/stat.h>
   59 #include <sys/mount.h>
   60 #include <sys/namei.h>
   61 #include <sys/buf.h>
   62 #include <sys/dirent.h>
   63 #include <sys/tty.h>
   64 
   65 #include <miscfs/fdesc/fdesc.h>
   66 #include <miscfs/genfs/genfs.h>
   67 
   68 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
   69 
   70 #define FDL_WANT        0x01
   71 #define FDL_LOCKED      0x02
   72 static int fdcache_lock;
   73 
   74 dev_t devctty;
   75 
   76 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
   77 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
   78 #endif
   79 
   80 #define NFDCACHE 4
   81 
   82 #define FD_NHASH(ix) \
   83         (&fdhashtbl[(ix) & fdhash])
   84 LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
   85 u_long fdhash;
   86 
   87 int     fdesc_lookup    __P((void *));
   88 #define fdesc_create    genfs_eopnotsupp
   89 #define fdesc_mknod     genfs_eopnotsupp
   90 int     fdesc_open      __P((void *));
   91 #define fdesc_close     genfs_nullop
   92 #define fdesc_access    genfs_nullop
   93 int     fdesc_getattr   __P((void *));
   94 int     fdesc_setattr   __P((void *));
   95 int     fdesc_read      __P((void *));
   96 int     fdesc_write     __P((void *));
   97 int     fdesc_ioctl     __P((void *));
   98 int     fdesc_poll      __P((void *));
   99 int     fdesc_kqfilter  __P((void *));
  100 #define fdesc_mmap      genfs_eopnotsupp
  101 #define fdesc_fcntl     genfs_fcntl
  102 #define fdesc_fsync     genfs_nullop
  103 #define fdesc_seek      genfs_seek
  104 #define fdesc_remove    genfs_eopnotsupp
  105 int     fdesc_link      __P((void *));
  106 #define fdesc_rename    genfs_eopnotsupp
  107 #define fdesc_mkdir     genfs_eopnotsupp
  108 #define fdesc_rmdir     genfs_eopnotsupp
  109 int     fdesc_symlink   __P((void *));
  110 int     fdesc_readdir   __P((void *));
  111 int     fdesc_readlink  __P((void *));
  112 #define fdesc_abortop   genfs_abortop
  113 int     fdesc_inactive  __P((void *));
  114 int     fdesc_reclaim   __P((void *));
  115 #define fdesc_lock      genfs_lock
  116 #define fdesc_unlock    genfs_unlock
  117 #define fdesc_bmap      genfs_badop
  118 #define fdesc_strategy  genfs_badop
  119 int     fdesc_print     __P((void *));
  120 int     fdesc_pathconf  __P((void *));
  121 #define fdesc_islocked  genfs_islocked
  122 #define fdesc_advlock   genfs_einval
  123 #define fdesc_blkatoff  genfs_eopnotsupp
  124 #define fdesc_valloc    genfs_eopnotsupp
  125 #define fdesc_vfree     genfs_nullop
  126 #define fdesc_truncate  genfs_eopnotsupp
  127 #define fdesc_update    genfs_nullop
  128 #define fdesc_bwrite    genfs_eopnotsupp
  129 #define fdesc_revoke    genfs_revoke
  130 #define fdesc_putpages  genfs_null_putpages
  131 
  132 static int fdesc_attr __P((int, struct vattr *, struct ucred *, struct proc *));
  133 
  134 int (**fdesc_vnodeop_p) __P((void *));
  135 const struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
  136         { &vop_default_desc, vn_default_error },
  137         { &vop_lookup_desc, fdesc_lookup },             /* lookup */
  138         { &vop_create_desc, fdesc_create },             /* create */
  139         { &vop_mknod_desc, fdesc_mknod },               /* mknod */
  140         { &vop_open_desc, fdesc_open },                 /* open */
  141         { &vop_close_desc, fdesc_close },               /* close */
  142         { &vop_access_desc, fdesc_access },             /* access */
  143         { &vop_getattr_desc, fdesc_getattr },           /* getattr */
  144         { &vop_setattr_desc, fdesc_setattr },           /* setattr */
  145         { &vop_read_desc, fdesc_read },                 /* read */
  146         { &vop_write_desc, fdesc_write },               /* write */
  147         { &vop_ioctl_desc, fdesc_ioctl },               /* ioctl */
  148         { &vop_fcntl_desc, fdesc_fcntl },               /* fcntl */
  149         { &vop_poll_desc, fdesc_poll },                 /* poll */
  150         { &vop_kqfilter_desc, fdesc_kqfilter },         /* kqfilter */
  151         { &vop_revoke_desc, fdesc_revoke },             /* revoke */
  152         { &vop_mmap_desc, fdesc_mmap },                 /* mmap */
  153         { &vop_fsync_desc, fdesc_fsync },               /* fsync */
  154         { &vop_seek_desc, fdesc_seek },                 /* seek */
  155         { &vop_remove_desc, fdesc_remove },             /* remove */
  156         { &vop_link_desc, fdesc_link },                 /* link */
  157         { &vop_rename_desc, fdesc_rename },             /* rename */
  158         { &vop_mkdir_desc, fdesc_mkdir },               /* mkdir */
  159         { &vop_rmdir_desc, fdesc_rmdir },               /* rmdir */
  160         { &vop_symlink_desc, fdesc_symlink },           /* symlink */
  161         { &vop_readdir_desc, fdesc_readdir },           /* readdir */
  162         { &vop_readlink_desc, fdesc_readlink },         /* readlink */
  163         { &vop_abortop_desc, fdesc_abortop },           /* abortop */
  164         { &vop_inactive_desc, fdesc_inactive },         /* inactive */
  165         { &vop_reclaim_desc, fdesc_reclaim },           /* reclaim */
  166         { &vop_lock_desc, fdesc_lock },                 /* lock */
  167         { &vop_unlock_desc, fdesc_unlock },             /* unlock */
  168         { &vop_bmap_desc, fdesc_bmap },                 /* bmap */
  169         { &vop_strategy_desc, fdesc_strategy },         /* strategy */
  170         { &vop_print_desc, fdesc_print },               /* print */
  171         { &vop_islocked_desc, fdesc_islocked },         /* islocked */
  172         { &vop_pathconf_desc, fdesc_pathconf },         /* pathconf */
  173         { &vop_advlock_desc, fdesc_advlock },           /* advlock */
  174         { &vop_blkatoff_desc, fdesc_blkatoff },         /* blkatoff */
  175         { &vop_valloc_desc, fdesc_valloc },             /* valloc */
  176         { &vop_vfree_desc, fdesc_vfree },               /* vfree */
  177         { &vop_truncate_desc, fdesc_truncate },         /* truncate */
  178         { &vop_update_desc, fdesc_update },             /* update */
  179         { &vop_bwrite_desc, fdesc_bwrite },             /* bwrite */
  180         { &vop_putpages_desc, fdesc_putpages },         /* putpages */
  181         { NULL, NULL }
  182 };
  183 
  184 const struct vnodeopv_desc fdesc_vnodeop_opv_desc =
  185         { &fdesc_vnodeop_p, fdesc_vnodeop_entries };
  186 
  187 extern const struct cdevsw ctty_cdevsw;
  188 
  189 /*
  190  * Initialise cache headers
  191  */
  192 void
  193 fdesc_init()
  194 {
  195         int cttymajor;
  196 
  197         /* locate the major number */
  198         cttymajor = cdevsw_lookup_major(&ctty_cdevsw);
  199         devctty = makedev(cttymajor, 0);
  200         fdhashtbl = hashinit(NFDCACHE, HASH_LIST, M_CACHE, M_NOWAIT, &fdhash);
  201 }
  202 
  203 /*
  204  * Free hash table.
  205  */
  206 void
  207 fdesc_done()
  208 {
  209         hashdone(fdhashtbl, M_CACHE);
  210 }
  211 
  212 /*
  213  * Return a locked vnode of the correct type.
  214  */
  215 int
  216 fdesc_allocvp(ftype, ix, mp, vpp)
  217         fdntype ftype;
  218         int ix;
  219         struct mount *mp;
  220         struct vnode **vpp;
  221 {
  222         struct fdhashhead *fc;
  223         struct fdescnode *fd;
  224         int error = 0;
  225 
  226         fc = FD_NHASH(ix);
  227 loop:
  228         for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
  229                 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
  230                         if (vget(fd->fd_vnode, LK_EXCLUSIVE))
  231                                 goto loop;
  232                         *vpp = fd->fd_vnode;
  233                         return (error);
  234                 }
  235         }
  236 
  237         /*
  238          * otherwise lock the array while we call getnewvnode
  239          * since that can block.
  240          */
  241         if (fdcache_lock & FDL_LOCKED) {
  242                 fdcache_lock |= FDL_WANT;
  243                 (void) tsleep(&fdcache_lock, PINOD, "fdcache", 0);
  244                 goto loop;
  245         }
  246         fdcache_lock |= FDL_LOCKED;
  247 
  248         error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
  249         if (error)
  250                 goto out;
  251         MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
  252         (*vpp)->v_data = fd;
  253         fd->fd_vnode = *vpp;
  254         fd->fd_type = ftype;
  255         fd->fd_fd = -1;
  256         fd->fd_link = 0;
  257         fd->fd_ix = ix;
  258         VOP_LOCK(*vpp, LK_EXCLUSIVE);
  259         LIST_INSERT_HEAD(fc, fd, fd_hash);
  260 
  261 out:;
  262         fdcache_lock &= ~FDL_LOCKED;
  263 
  264         if (fdcache_lock & FDL_WANT) {
  265                 fdcache_lock &= ~FDL_WANT;
  266                 wakeup(&fdcache_lock);
  267         }
  268 
  269         return (error);
  270 }
  271 
  272 /*
  273  * vp is the current namei directory
  274  * ndp is the name to locate in that directory...
  275  */
  276 int
  277 fdesc_lookup(v)
  278         void *v;
  279 {
  280         struct vop_lookup_args /* {
  281                 struct vnode * a_dvp;
  282                 struct vnode ** a_vpp;
  283                 struct componentname * a_cnp;
  284         } */ *ap = v;
  285         struct vnode **vpp = ap->a_vpp;
  286         struct vnode *dvp = ap->a_dvp;
  287         struct componentname *cnp = ap->a_cnp;
  288         struct proc *p = cnp->cn_proc;
  289         const char *pname = cnp->cn_nameptr;
  290         int nfiles = p->p_fd->fd_nfiles;
  291         unsigned fd = 0;
  292         int error;
  293         struct vnode *fvp;
  294         char *ln;
  295 
  296         if (cnp->cn_namelen == 1 && *pname == '.') {
  297                 *vpp = dvp;
  298                 VREF(dvp);
  299                 return (0);
  300         }
  301 
  302         switch (VTOFDESC(dvp)->fd_type) {
  303         default:
  304         case Flink:
  305         case Fdesc:
  306         case Fctty:
  307                 error = ENOTDIR;
  308                 goto bad;
  309 
  310         case Froot:
  311                 if (cnp->cn_namelen == 2 && memcmp(pname, "fd", 2) == 0) {
  312                         error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
  313                         if (error)
  314                                 goto bad;
  315                         *vpp = fvp;
  316                         fvp->v_type = VDIR;
  317                         goto good;
  318                 }
  319 
  320                 if (cnp->cn_namelen == 3 && memcmp(pname, "tty", 3) == 0) {
  321                         struct vnode *ttyvp = cttyvp(p);
  322                         if (ttyvp == NULL) {
  323                                 error = ENXIO;
  324                                 goto bad;
  325                         }
  326                         error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
  327                         if (error)
  328                                 goto bad;
  329                         *vpp = fvp;
  330                         fvp->v_type = VCHR;
  331                         goto good;
  332                 }
  333 
  334                 ln = 0;
  335                 switch (cnp->cn_namelen) {
  336                 case 5:
  337                         if (memcmp(pname, "stdin", 5) == 0) {
  338                                 ln = "fd/0";
  339                                 fd = FD_STDIN;
  340                         }
  341                         break;
  342                 case 6:
  343                         if (memcmp(pname, "stdout", 6) == 0) {
  344                                 ln = "fd/1";
  345                                 fd = FD_STDOUT;
  346                         } else
  347                         if (memcmp(pname, "stderr", 6) == 0) {
  348                                 ln = "fd/2";
  349                                 fd = FD_STDERR;
  350                         }
  351                         break;
  352                 }
  353 
  354                 if (ln) {
  355                         error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
  356                         if (error)
  357                                 goto bad;
  358                         VTOFDESC(fvp)->fd_link = ln;
  359                         *vpp = fvp;
  360                         fvp->v_type = VLNK;
  361                         goto good;
  362                 } else {
  363                         error = ENOENT;
  364                         goto bad;
  365                 }
  366 
  367                 /* FALL THROUGH */
  368 
  369         case Fdevfd:
  370                 if (cnp->cn_namelen == 2 && memcmp(pname, "..", 2) == 0) {
  371                         VOP_UNLOCK(dvp, 0);
  372                         cnp->cn_flags |= PDIRUNLOCK;
  373                         error = fdesc_root(dvp->v_mount, vpp);
  374                         if (error)
  375                                 goto bad;
  376                         /*
  377                          * If we're at the last component and need the
  378                          * parent locked, undo the unlock above.
  379                          */
  380                         if (((~cnp->cn_flags & (ISLASTCN | LOCKPARENT)) == 0) &&
  381                                    ((error = vn_lock(dvp, LK_EXCLUSIVE)) == 0))
  382                                 cnp->cn_flags &= ~PDIRUNLOCK;
  383                         return (error);
  384                 }
  385 
  386                 fd = 0;
  387                 while (*pname >= '' && *pname <= '9') {
  388                         fd = 10 * fd + *pname++ - '';
  389                         if (fd >= nfiles)
  390                                 break;
  391                 }
  392 
  393                 if (*pname != '\0') {
  394                         error = ENOENT;
  395                         goto bad;
  396                 }
  397 
  398                 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL ||
  399                     FILE_IS_USABLE(p->p_fd->fd_ofiles[fd]) == 0) {
  400                         error = EBADF;
  401                         goto bad;
  402                 }
  403 
  404                 error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
  405                 if (error)
  406                         goto bad;
  407                 VTOFDESC(fvp)->fd_fd = fd;
  408                 *vpp = fvp;
  409                 goto good;
  410         }
  411 
  412 bad:;
  413         *vpp = NULL;
  414         return (error);
  415 
  416 good:;
  417         /*
  418          * As "." was special cased above, we now unlock the parent if we're
  419          * suppoed to. We're only supposed to not unlock if this is the
  420          * last component, and the caller requested LOCKPARENT. So if either
  421          * condition is false, unlock.
  422          */
  423         if (((~cnp->cn_flags) & (ISLASTCN | LOCKPARENT)) != 0) {
  424                 VOP_UNLOCK(dvp, 0);
  425                 cnp->cn_flags |= PDIRUNLOCK;
  426         }
  427         return (0);
  428 }
  429 
  430 int
  431 fdesc_open(v)
  432         void *v;
  433 {
  434         struct vop_open_args /* {
  435                 struct vnode *a_vp;
  436                 int  a_mode;
  437                 struct ucred *a_cred;
  438                 struct proc *a_p;
  439         } */ *ap = v;
  440         struct vnode *vp = ap->a_vp;
  441 
  442         switch (VTOFDESC(vp)->fd_type) {
  443         case Fdesc:
  444                 /*
  445                  * XXX Kludge: set dupfd to contain the value of the
  446                  * the file descriptor being sought for duplication. The error
  447                  * return ensures that the vnode for this device will be
  448                  * released by vn_open. Open will detect this special error and
  449                  * take the actions in dupfdopen.  Other callers of vn_open or
  450                  * VOP_OPEN will simply report the error.
  451                  */
  452                 curlwp->l_dupfd = VTOFDESC(vp)->fd_fd;  /* XXX */
  453                 return EDUPFD;
  454 
  455         case Fctty:
  456                 return ((*ctty_cdevsw.d_open)(devctty, ap->a_mode, 0, ap->a_p));
  457         case Froot:
  458         case Fdevfd:
  459         case Flink:
  460                 break;
  461         }
  462 
  463         return (0);
  464 }
  465 
  466 static int
  467 fdesc_attr(fd, vap, cred, p)
  468         int fd;
  469         struct vattr *vap;
  470         struct ucred *cred;
  471         struct proc *p;
  472 {
  473         struct filedesc *fdp = p->p_fd;
  474         struct file *fp;
  475         struct stat stb;
  476         int error;
  477 
  478         if ((fp = fd_getfile(fdp, fd)) == NULL)
  479                 return (EBADF);
  480 
  481         switch (fp->f_type) {
  482         case DTYPE_VNODE:
  483                 simple_unlock(&fp->f_slock);
  484                 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
  485                 if (error == 0 && vap->va_type == VDIR) {
  486                         /*
  487                          * directories can cause loops in the namespace,
  488                          * so turn off the 'x' bits to avoid trouble.
  489                          */
  490                         vap->va_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
  491                 }
  492                 break;
  493 
  494         default:
  495                 FILE_USE(fp);
  496                 memset(&stb, 0, sizeof(stb));
  497                 error = (*fp->f_ops->fo_stat)(fp, &stb, p);
  498                 FILE_UNUSE(fp, p);
  499                 if (error)
  500                         break;
  501 
  502                 vattr_null(vap);
  503                 switch(fp->f_type) {
  504                 case DTYPE_SOCKET:
  505                         vap->va_type = VSOCK;
  506                         break;
  507                 case DTYPE_PIPE:
  508                         vap->va_type = VFIFO;
  509                         break;
  510                 default:
  511                         /* use VNON perhaps? */
  512                         vap->va_type = VBAD;
  513                         break;
  514                 }
  515                 vap->va_mode = stb.st_mode;
  516                 vap->va_nlink = stb.st_nlink;
  517                 vap->va_uid = stb.st_uid;
  518                 vap->va_gid = stb.st_gid;
  519                 vap->va_fsid = stb.st_dev;
  520                 vap->va_fileid = stb.st_ino;
  521                 vap->va_size = stb.st_size;
  522                 vap->va_blocksize = stb.st_blksize;
  523                 vap->va_atime = stb.st_atimespec;
  524                 vap->va_mtime = stb.st_mtimespec;
  525                 vap->va_ctime = stb.st_ctimespec;
  526                 vap->va_gen = stb.st_gen;
  527                 vap->va_flags = stb.st_flags;
  528                 vap->va_rdev = stb.st_rdev;
  529                 vap->va_bytes = stb.st_blocks * stb.st_blksize;
  530                 break;
  531         }
  532 
  533         return (error);
  534 }
  535 
  536 int
  537 fdesc_getattr(v)
  538         void *v;
  539 {
  540         struct vop_getattr_args /* {
  541                 struct vnode *a_vp;
  542                 struct vattr *a_vap;
  543                 struct ucred *a_cred;
  544                 struct proc *a_p;
  545         } */ *ap = v;
  546         struct vnode *vp = ap->a_vp;
  547         struct vattr *vap = ap->a_vap;
  548         unsigned fd;
  549         int error = 0;
  550 
  551         switch (VTOFDESC(vp)->fd_type) {
  552         case Froot:
  553         case Fdevfd:
  554         case Flink:
  555         case Fctty:
  556                 VATTR_NULL(vap);
  557                 vap->va_fileid = VTOFDESC(vp)->fd_ix;
  558 
  559 #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH)
  560 #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH)
  561 #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH)
  562 
  563                 switch (VTOFDESC(vp)->fd_type) {
  564                 case Flink:
  565                         vap->va_mode = R_ALL|X_ALL;
  566                         vap->va_type = VLNK;
  567                         vap->va_rdev = 0;
  568                         vap->va_nlink = 1;
  569                         vap->va_size = strlen(VTOFDESC(vp)->fd_link);
  570                         break;
  571 
  572                 case Fctty:
  573                         vap->va_mode = R_ALL|W_ALL;
  574                         vap->va_type = VCHR;
  575                         vap->va_rdev = devctty;
  576                         vap->va_nlink = 1;
  577                         vap->va_size = 0;
  578                         break;
  579 
  580                 default:
  581                         vap->va_mode = R_ALL|X_ALL;
  582                         vap->va_type = VDIR;
  583                         vap->va_rdev = 0;
  584                         vap->va_nlink = 2;
  585                         vap->va_size = DEV_BSIZE;
  586                         break;
  587                 }
  588                 vap->va_uid = 0;
  589                 vap->va_gid = 0;
  590                 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
  591                 vap->va_blocksize = DEV_BSIZE;
  592                 vap->va_atime.tv_sec = boottime.tv_sec;
  593                 vap->va_atime.tv_nsec = 0;
  594                 vap->va_mtime = vap->va_atime;
  595                 vap->va_ctime = vap->va_mtime;
  596                 vap->va_gen = 0;
  597                 vap->va_flags = 0;
  598                 vap->va_bytes = 0;
  599                 break;
  600 
  601         case Fdesc:
  602                 fd = VTOFDESC(vp)->fd_fd;
  603                 error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
  604                 break;
  605 
  606         default:
  607                 panic("fdesc_getattr");
  608                 break;
  609         }
  610 
  611         if (error == 0)
  612                 vp->v_type = vap->va_type;
  613 
  614         return (error);
  615 }
  616 
  617 int
  618 fdesc_setattr(v)
  619         void *v;
  620 {
  621         struct vop_setattr_args /* {
  622                 struct vnode *a_vp;
  623                 struct vattr *a_vap;
  624                 struct ucred *a_cred;
  625                 struct proc *a_p;
  626         } */ *ap = v;
  627         struct filedesc *fdp = ap->a_p->p_fd;
  628         struct file *fp;
  629         unsigned fd;
  630 
  631         /*
  632          * Can't mess with the root vnode
  633          */
  634         switch (VTOFDESC(ap->a_vp)->fd_type) {
  635         case Fdesc:
  636                 break;
  637 
  638         case Fctty:
  639                 return (0);
  640 
  641         default:
  642                 return (EACCES);
  643         }
  644 
  645         fd = VTOFDESC(ap->a_vp)->fd_fd;
  646         if ((fp = fd_getfile(fdp, fd)) == NULL)
  647                 return (EBADF);
  648 
  649         /*
  650          * XXX: Can't reasonably set the attr's on any types currently.
  651          *      On vnode's this will cause truncation and socket/pipes make
  652          *      no sense.
  653          */
  654         simple_unlock(&fp->f_slock);
  655         return (0);
  656 }
  657 
  658 #define UIO_MX 32
  659 
  660 struct fdesc_target {
  661         ino_t ft_fileno;
  662         u_char ft_type;
  663         u_char ft_namlen;
  664         char *ft_name;
  665 } fdesc_targets[] = {
  666 /* NOTE: The name must be less than UIO_MX-16 chars in length */
  667 #define N(s) sizeof(s)-1, s
  668         { FD_DEVFD,  DT_DIR,     N("fd")     },
  669         { FD_STDIN,  DT_LNK,     N("stdin")  },
  670         { FD_STDOUT, DT_LNK,     N("stdout") },
  671         { FD_STDERR, DT_LNK,     N("stderr") },
  672         { FD_CTTY,   DT_UNKNOWN, N("tty")    },
  673 #undef N
  674 };
  675 static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]);
  676 
  677 int
  678 fdesc_readdir(v)
  679         void *v;
  680 {
  681         struct vop_readdir_args /* {
  682                 struct vnode *a_vp;
  683                 struct uio *a_uio;
  684                 struct ucred *a_cred;
  685                 int *a_eofflag;
  686                 off_t **a_cookies;
  687                 int *a_ncookies;
  688         } */ *ap = v;
  689         struct uio *uio = ap->a_uio;
  690         struct dirent d;
  691         struct filedesc *fdp;
  692         off_t i;
  693         int error;
  694         off_t *cookies = NULL;
  695         int ncookies = 0;
  696 
  697         switch (VTOFDESC(ap->a_vp)->fd_type) {
  698         case Fctty:
  699                 return (0);
  700 
  701         case Fdesc:
  702                 return (ENOTDIR);
  703 
  704         default:
  705                 break;
  706         }
  707 
  708         fdp = uio->uio_procp->p_fd;
  709 
  710         if (uio->uio_resid < UIO_MX)
  711                 return (EINVAL);
  712         if (uio->uio_offset < 0)
  713                 return (EINVAL);
  714 
  715         error = 0;
  716         i = uio->uio_offset;
  717         memset(&d, 0, UIO_MX);
  718         d.d_reclen = UIO_MX;
  719         if (ap->a_ncookies)
  720                 ncookies = (uio->uio_resid / UIO_MX);
  721 
  722         if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
  723                 struct fdesc_target *ft;
  724 
  725                 if (i >= nfdesc_targets)
  726                         return 0;
  727 
  728                 if (ap->a_ncookies) {
  729                         ncookies = min(ncookies, (nfdesc_targets - i));
  730                         cookies = malloc(ncookies * sizeof(off_t),
  731                             M_TEMP, M_WAITOK);
  732                         *ap->a_cookies = cookies;
  733                         *ap->a_ncookies = ncookies;
  734                 }
  735 
  736                 for (ft = &fdesc_targets[i];
  737                      uio->uio_resid >= UIO_MX && i < nfdesc_targets; ft++, i++) {
  738                         switch (ft->ft_fileno) {
  739                         case FD_CTTY:
  740                                 if (cttyvp(uio->uio_procp) == NULL)
  741                                         continue;
  742                                 break;
  743 
  744                         case FD_STDIN:
  745                         case FD_STDOUT:
  746                         case FD_STDERR:
  747                                 if ((ft->ft_fileno - FD_STDIN) >= fdp->fd_nfiles)
  748                                         continue;
  749                                 if (fdp->fd_ofiles[ft->ft_fileno - FD_STDIN] == NULL
  750                                     || FILE_IS_USABLE(fdp->fd_ofiles[ft->ft_fileno - FD_STDIN]) == 0)
  751                                         continue;
  752                                 break;
  753                         }
  754 
  755                         d.d_fileno = ft->ft_fileno;
  756                         d.d_namlen = ft->ft_namlen;
  757                         memcpy(d.d_name, ft->ft_name, ft->ft_namlen + 1);
  758                         d.d_type = ft->ft_type;
  759 
  760                         if ((error = uiomove(&d, UIO_MX, uio)) != 0)
  761                                 break;
  762                         if (cookies)
  763                                 *cookies++ = i + 1;
  764                 }
  765         } else {
  766                 if (ap->a_ncookies) {
  767                         ncookies = min(ncookies, (fdp->fd_nfiles + 2));
  768                         cookies = malloc(ncookies * sizeof(off_t),
  769                             M_TEMP, M_WAITOK);
  770                         *ap->a_cookies = cookies;
  771                         *ap->a_ncookies = ncookies;
  772                 }
  773                 for (; i - 2 < fdp->fd_nfiles && uio->uio_resid >= UIO_MX;
  774                      i++) {
  775                         switch (i) {
  776                         case 0:
  777                         case 1:
  778                                 d.d_fileno = FD_ROOT;           /* XXX */
  779                                 d.d_namlen = i + 1;
  780                                 memcpy(d.d_name, "..", d.d_namlen);
  781                                 d.d_name[i + 1] = '\0';
  782                                 d.d_type = DT_DIR;
  783                                 break;
  784 
  785                         default:
  786                                 if (fdp->fd_ofiles[i - 2] == NULL ||
  787                                     FILE_IS_USABLE(fdp->fd_ofiles[i - 2]) == 0)
  788                                         continue;
  789                                 d.d_fileno = i - 2 + FD_STDIN;
  790                                 d.d_namlen = sprintf(d.d_name, "%d", (int) i - 2);
  791                                 d.d_type = DT_UNKNOWN;
  792                                 break;
  793                         }
  794 
  795                         if ((error = uiomove(&d, UIO_MX, uio)) != 0)
  796                                 break;
  797                         if (cookies)
  798                                 *cookies++ = i + 1;
  799                 }
  800         }
  801 
  802         if (ap->a_ncookies && error) {
  803                 free(*ap->a_cookies, M_TEMP);
  804                 *ap->a_ncookies = 0;
  805                 *ap->a_cookies = NULL;
  806         }
  807 
  808         uio->uio_offset = i;
  809         return (error);
  810 }
  811 
  812 int
  813 fdesc_readlink(v)
  814         void *v;
  815 {
  816         struct vop_readlink_args /* {
  817                 struct vnode *a_vp;
  818                 struct uio *a_uio;
  819                 struct ucred *a_cred;
  820         } */ *ap = v;
  821         struct vnode *vp = ap->a_vp;
  822         int error;
  823 
  824         if (vp->v_type != VLNK)
  825                 return (EPERM);
  826 
  827         if (VTOFDESC(vp)->fd_type == Flink) {
  828                 char *ln = VTOFDESC(vp)->fd_link;
  829                 error = uiomove(ln, strlen(ln), ap->a_uio);
  830         } else {
  831                 error = EOPNOTSUPP;
  832         }
  833 
  834         return (error);
  835 }
  836 
  837 int
  838 fdesc_read(v)
  839         void *v;
  840 {
  841         struct vop_read_args /* {
  842                 struct vnode *a_vp;
  843                 struct uio *a_uio;
  844                 int  a_ioflag;
  845                 struct ucred *a_cred;
  846         } */ *ap = v;
  847         int error = EOPNOTSUPP;
  848         struct vnode *vp = ap->a_vp;
  849 
  850         switch (VTOFDESC(vp)->fd_type) {
  851         case Fctty:
  852                 VOP_UNLOCK(vp, 0);
  853                 error = (*ctty_cdevsw.d_read)(devctty, ap->a_uio, ap->a_ioflag);
  854                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  855                 break;
  856 
  857         default:
  858                 error = EOPNOTSUPP;
  859                 break;
  860         }
  861 
  862         return (error);
  863 }
  864 
  865 int
  866 fdesc_write(v)
  867         void *v;
  868 {
  869         struct vop_write_args /* {
  870                 struct vnode *a_vp;
  871                 struct uio *a_uio;
  872                 int  a_ioflag;
  873                 struct ucred *a_cred;
  874         } */ *ap = v;
  875         int error = EOPNOTSUPP;
  876         struct vnode *vp = ap->a_vp;
  877 
  878         switch (VTOFDESC(vp)->fd_type) {
  879         case Fctty:
  880                 VOP_UNLOCK(vp, 0);
  881                 error = (*ctty_cdevsw.d_write)(devctty, ap->a_uio,
  882                                                ap->a_ioflag);
  883                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  884                 break;
  885 
  886         default:
  887                 error = EOPNOTSUPP;
  888                 break;
  889         }
  890 
  891         return (error);
  892 }
  893 
  894 int
  895 fdesc_ioctl(v)
  896         void *v;
  897 {
  898         struct vop_ioctl_args /* {
  899                 struct vnode *a_vp;
  900                 u_long a_command;
  901                 void *a_data;
  902                 int  a_fflag;
  903                 struct ucred *a_cred;
  904                 struct proc *a_p;
  905         } */ *ap = v;
  906         int error = EOPNOTSUPP;
  907 
  908         switch (VTOFDESC(ap->a_vp)->fd_type) {
  909         case Fctty:
  910                 error = (*ctty_cdevsw.d_ioctl)(devctty, ap->a_command,
  911                                                ap->a_data, ap->a_fflag,
  912                                                ap->a_p);
  913                 break;
  914 
  915         default:
  916                 error = EOPNOTSUPP;
  917                 break;
  918         }
  919 
  920         return (error);
  921 }
  922 
  923 int
  924 fdesc_poll(v)
  925         void *v;
  926 {
  927         struct vop_poll_args /* {
  928                 struct vnode *a_vp;
  929                 int a_events;
  930                 struct proc *a_p;
  931         } */ *ap = v;
  932         int revents;
  933 
  934         switch (VTOFDESC(ap->a_vp)->fd_type) {
  935         case Fctty:
  936                 revents = (*ctty_cdevsw.d_poll)(devctty, ap->a_events, ap->a_p);
  937                 break;
  938 
  939         default:
  940                 revents = genfs_poll(v);
  941                 break;
  942         }
  943 
  944         return (revents);
  945 }
  946 
  947 int
  948 fdesc_kqfilter(v)
  949         void *v;
  950 {
  951         struct vop_kqfilter_args /* {
  952                 struct vnode *a_vp;
  953                 struct knote *a_kn;
  954         } */ *ap = v;
  955         int error;
  956         struct proc *p;
  957         struct file *fp;
  958 
  959         switch (VTOFDESC(ap->a_vp)->fd_type) {
  960         case Fctty:
  961                 error = (*ctty_cdevsw.d_kqfilter)(devctty, ap->a_kn);
  962                 break;
  963 
  964         case Fdesc:
  965                 /* just invoke kqfilter for the underlying descriptor */
  966                 p = curproc;    /* XXX hopefully ok to use curproc here */
  967                 if ((fp = fd_getfile(p->p_fd, VTOFDESC(ap->a_vp)->fd_fd)) == NULL)
  968                         return (1);
  969 
  970                 FILE_USE(fp);
  971                 error = (*fp->f_ops->fo_kqfilter)(fp, ap->a_kn);
  972                 FILE_UNUSE(fp, p);
  973                 break;
  974 
  975         default:
  976                 return (genfs_kqfilter(v));
  977         }
  978 
  979         return (error);
  980 }
  981 
  982 int
  983 fdesc_inactive(v)
  984         void *v;
  985 {
  986         struct vop_inactive_args /* {
  987                 struct vnode *a_vp;
  988                 struct proc *a_p;
  989         } */ *ap = v;
  990         struct vnode *vp = ap->a_vp;
  991 
  992         /*
  993          * Clear out the v_type field to avoid
  994          * nasty things happening in vgone().
  995          */
  996         VOP_UNLOCK(vp, 0);
  997         vp->v_type = VNON;
  998         return (0);
  999 }
 1000 
 1001 int
 1002 fdesc_reclaim(v)
 1003         void *v;
 1004 {
 1005         struct vop_reclaim_args /* {
 1006                 struct vnode *a_vp;
 1007         } */ *ap = v;
 1008         struct vnode *vp = ap->a_vp;
 1009         struct fdescnode *fd = VTOFDESC(vp);
 1010 
 1011         LIST_REMOVE(fd, fd_hash);
 1012         FREE(vp->v_data, M_TEMP);
 1013         vp->v_data = 0;
 1014 
 1015         return (0);
 1016 }
 1017 
 1018 /*
 1019  * Return POSIX pathconf information applicable to special devices.
 1020  */
 1021 int
 1022 fdesc_pathconf(v)
 1023         void *v;
 1024 {
 1025         struct vop_pathconf_args /* {
 1026                 struct vnode *a_vp;
 1027                 int a_name;
 1028                 register_t *a_retval;
 1029         } */ *ap = v;
 1030 
 1031         switch (ap->a_name) {
 1032         case _PC_LINK_MAX:
 1033                 *ap->a_retval = LINK_MAX;
 1034                 return (0);
 1035         case _PC_MAX_CANON:
 1036                 *ap->a_retval = MAX_CANON;
 1037                 return (0);
 1038         case _PC_MAX_INPUT:
 1039                 *ap->a_retval = MAX_INPUT;
 1040                 return (0);
 1041         case _PC_PIPE_BUF:
 1042                 *ap->a_retval = PIPE_BUF;
 1043                 return (0);
 1044         case _PC_CHOWN_RESTRICTED:
 1045                 *ap->a_retval = 1;
 1046                 return (0);
 1047         case _PC_VDISABLE:
 1048                 *ap->a_retval = _POSIX_VDISABLE;
 1049                 return (0);
 1050         case _PC_SYNC_IO:
 1051                 *ap->a_retval = 1;
 1052                 return (0);
 1053         default:
 1054                 return (EINVAL);
 1055         }
 1056         /* NOTREACHED */
 1057 }
 1058 
 1059 /*
 1060  * Print out the contents of a /dev/fd vnode.
 1061  */
 1062 /* ARGSUSED */
 1063 int
 1064 fdesc_print(v)
 1065         void *v;
 1066 {
 1067         printf("tag VT_NON, fdesc vnode\n");
 1068         return (0);
 1069 }
 1070 
 1071 int
 1072 fdesc_link(v)
 1073         void *v;
 1074 {
 1075         struct vop_link_args /* {
 1076                 struct vnode *a_dvp;
 1077                 struct vnode *a_vp;
 1078                 struct componentname *a_cnp;
 1079         } */ *ap = v;
 1080 
 1081         VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
 1082         vput(ap->a_dvp);
 1083         return (EROFS);
 1084 }
 1085 
 1086 int
 1087 fdesc_symlink(v)
 1088         void *v;
 1089 {
 1090         struct vop_symlink_args /* {
 1091                 struct vnode *a_dvp;
 1092                 struct vnode **a_vpp;
 1093                 struct componentname *a_cnp;
 1094                 struct vattr *a_vap;
 1095                 char *a_target;
 1096         } */ *ap = v;
 1097 
 1098         VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
 1099         vput(ap->a_dvp);
 1100         return (EROFS);
 1101 }

Cache object: 8257b9578c4116a62fa4e0ad477102be


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