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/fs/pseudofs/pseudofs_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 /*-
    2  * Copyright (c) 2001 Dag-Erling Co´dan Sm°rgrav
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  *      $FreeBSD: releng/5.0/sys/fs/pseudofs/pseudofs_vnops.c 120979 2003-10-10 20:15:49Z nectar $
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/systm.h>
   34 #include <sys/ctype.h>
   35 #include <sys/dirent.h>
   36 #include <sys/fcntl.h>
   37 #include <sys/lock.h>
   38 #include <sys/mount.h>
   39 #include <sys/mutex.h>
   40 #include <sys/namei.h>
   41 #include <sys/proc.h>
   42 #include <sys/sbuf.h>
   43 #include <sys/sx.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/vnode.h>
   46 #include <machine/limits.h>
   47 
   48 #include <fs/pseudofs/pseudofs.h>
   49 #include <fs/pseudofs/pseudofs_internal.h>
   50 
   51 #if 0
   52 #define PFS_TRACE(foo) \
   53         do { \
   54                 printf("pseudofs: %s(): line %d: ", __func__, __LINE__); \
   55                 printf foo ; \
   56                 printf("\n"); \
   57         } while (0)
   58 #define PFS_RETURN(err) \
   59         do { \
   60                 printf("pseudofs: %s(): line %d: returning %d\n", \
   61                     __func__, __LINE__, err); \
   62                 return (err); \
   63         } while (0)
   64 #else
   65 #define PFS_TRACE(foo) \
   66         do { /* nothing */ } while (0)
   67 #define PFS_RETURN(err) \
   68         return (err)
   69 #endif
   70 
   71 /*
   72  * Returns non-zero if given file is visible to given process
   73  */
   74 static int
   75 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid)
   76 {
   77         struct proc *proc;
   78         int r;
   79 
   80         PFS_TRACE(("%s (pid: %d, req: %d)",
   81             pn->pn_name, pid, td->td_proc->p_pid));
   82 
   83         if (pn->pn_flags & PFS_DISABLED)
   84                 PFS_RETURN (0);
   85 
   86         r = 1;
   87         if (pid != NO_PID) {
   88                 if ((proc = pfind(pid)) == NULL)
   89                         PFS_RETURN (0);
   90                 if (p_cansee(td, proc) != 0 ||
   91                     (pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn)))
   92                         r = 0;
   93                 PROC_UNLOCK(proc);
   94         }
   95         PFS_RETURN (r);
   96 }
   97 
   98 /*
   99  * Verify permissions
  100  */
  101 static int
  102 pfs_access(struct vop_access_args *va)
  103 {
  104         struct vnode *vn = va->a_vp;
  105         struct vattr vattr;
  106         int error;
  107 
  108         PFS_TRACE((((struct pfs_vdata *)vn->v_data)->pvd_pn->pn_name));
  109 
  110         error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
  111         if (error)
  112                 PFS_RETURN (error);
  113         error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
  114             vattr.va_gid, va->a_mode, va->a_cred, NULL);
  115         PFS_RETURN (error);
  116 }
  117 
  118 /*
  119  * Close a file or directory
  120  */
  121 static int
  122 pfs_close(struct vop_close_args *va)
  123 {
  124         struct vnode *vn = va->a_vp;
  125         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  126         struct pfs_node *pn = pvd->pvd_pn;
  127         struct proc *proc;
  128         int error;
  129 
  130         PFS_TRACE((pn->pn_name));
  131 
  132         /*
  133          * Do nothing unless this is the last close and the node has a
  134          * last-close handler.
  135          */
  136         if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
  137                 PFS_RETURN (0);
  138 
  139         if (pvd->pvd_pid != NO_PID)
  140                 proc = pfind(pvd->pvd_pid);
  141         else
  142                 proc = NULL;
  143 
  144         error = (pn->pn_close)(va->a_td, proc, pn);
  145 
  146         if (proc != NULL)
  147                 PROC_UNLOCK(proc);
  148 
  149         PFS_RETURN (error);
  150 }
  151 
  152 /*
  153  * Get file attributes
  154  */
  155 static int
  156 pfs_getattr(struct vop_getattr_args *va)
  157 {
  158         struct vnode *vn = va->a_vp;
  159         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  160         struct pfs_node *pn = pvd->pvd_pn;
  161         struct vattr *vap = va->a_vap;
  162         struct proc *proc;
  163         int error = 0;
  164 
  165         PFS_TRACE((pn->pn_name));
  166 
  167         VATTR_NULL(vap);
  168         vap->va_type = vn->v_type;
  169         vap->va_fileid = pn->pn_fileno;
  170         vap->va_flags = 0;
  171         vap->va_blocksize = PAGE_SIZE;
  172         vap->va_bytes = vap->va_size = 0;
  173         vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
  174         vap->va_nlink = 1;
  175         nanotime(&vap->va_ctime);
  176         vap->va_atime = vap->va_mtime = vap->va_ctime;
  177 
  178         switch (pn->pn_type) {
  179         case pfstype_procdir:
  180         case pfstype_root:
  181         case pfstype_dir:
  182                 vap->va_mode = 0555;
  183                 break;
  184         case pfstype_file:
  185         case pfstype_symlink:
  186                 vap->va_mode = 0444;
  187                 break;
  188         default:
  189                 printf("shouldn't be here!\n");
  190                 vap->va_mode = 0;
  191                 break;
  192         }
  193 
  194         if (pvd->pvd_pid != NO_PID) {
  195                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  196                         PFS_RETURN (ENOENT);
  197                 vap->va_uid = proc->p_ucred->cr_ruid;
  198                 vap->va_gid = proc->p_ucred->cr_rgid;
  199                 if (pn->pn_attr != NULL)
  200                         error = (pn->pn_attr)(va->a_td, proc, pn, vap);
  201                 PROC_UNLOCK(proc);
  202         } else {
  203                 vap->va_uid = 0;
  204                 vap->va_gid = 0;
  205         }
  206 
  207         PFS_RETURN (error);
  208 }
  209 
  210 /*
  211  * Perform an ioctl
  212  */
  213 static int
  214 pfs_ioctl(struct vop_ioctl_args *va)
  215 {
  216         struct vnode *vn = va->a_vp;
  217         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  218         struct pfs_node *pn = pvd->pvd_pn;
  219         struct proc *proc = NULL;
  220         int error;
  221 
  222         PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
  223 
  224         if (vn->v_type != VREG)
  225                 PFS_RETURN (EINVAL);
  226 
  227         if (pn->pn_ioctl == NULL)
  228                 PFS_RETURN (ENOTTY);
  229 
  230         /*
  231          * This is necessary because either process' privileges may
  232          * have changed since the open() call.
  233          */
  234         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  235                 PFS_RETURN (EIO);
  236 
  237         /* XXX duplicates bits of pfs_visible() */
  238         if (pvd->pvd_pid != NO_PID) {
  239                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  240                         PFS_RETURN (EIO);
  241                 _PHOLD(proc);
  242                 PROC_UNLOCK(proc);
  243         }
  244 
  245         error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data);
  246 
  247         if (proc != NULL)
  248                 PRELE(proc);
  249 
  250         PFS_RETURN (error);
  251 }
  252 
  253 /*
  254  * Perform getextattr
  255  */
  256 static int
  257 pfs_getextattr(struct vop_getextattr_args *va)
  258 {
  259         struct vnode *vn = va->a_vp;
  260         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  261         struct pfs_node *pn = pvd->pvd_pn;
  262         struct proc *proc = NULL;
  263         int error;
  264 
  265         PFS_TRACE((pd->pn_name));
  266 
  267         if (pn->pn_getextattr == NULL)
  268                 PFS_RETURN (EOPNOTSUPP);
  269 
  270         /*
  271          * This is necessary because either process' privileges may
  272          * have changed since the open() call.
  273          */
  274         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  275                 PFS_RETURN (EIO);
  276 
  277         /* XXX duplicates bits of pfs_visible() */
  278         if (pvd->pvd_pid != NO_PID) {
  279                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  280                         PFS_RETURN (EIO);
  281                 _PHOLD(proc);
  282                 PROC_UNLOCK(proc);
  283         }
  284 
  285         error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
  286             va->a_name, va->a_uio, va->a_size, va->a_cred);
  287 
  288         if (proc != NULL)
  289                 PRELE(proc);
  290 
  291         PFS_RETURN (error);
  292 }
  293 
  294 /*
  295  * Look up a file or directory
  296  *
  297  * XXX NOTE!  pfs_lookup() has been hooked into vop_lookup_desc!  This
  298  * will result in a lookup operation for a vnode which may already be
  299  * cached, therefore we have to be careful to purge the VFS cache when
  300  * reusing a vnode.
  301  *
  302  * This code will work, but is not really correct.  Normally we would hook
  303  * vfs_cache_lookup() into vop_lookup_desc and hook pfs_lookup() into
  304  * vop_cachedlookup_desc.
  305  */
  306 static int
  307 pfs_lookup(struct vop_lookup_args *va)
  308 {
  309         struct vnode *vn = va->a_dvp;
  310         struct vnode **vpp = va->a_vpp;
  311         struct componentname *cnp = va->a_cnp;
  312         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  313         struct pfs_node *pd = pvd->pvd_pn;
  314         struct pfs_node *pn, *pdn = NULL;
  315         pid_t pid = pvd->pvd_pid;
  316         int lockparent;
  317         int wantparent;
  318         char *pname;
  319         int error, i, namelen;
  320 
  321         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
  322 
  323         cnp->cn_flags &= ~PDIRUNLOCK;
  324 
  325         if (vn->v_type != VDIR)
  326                 PFS_RETURN (ENOTDIR);
  327 
  328         /*
  329          * Don't support DELETE or RENAME.  CREATE is supported so
  330          * that O_CREAT will work, but the lookup will still fail if
  331          * the file does not exist.
  332          */
  333         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  334                 PFS_RETURN (EOPNOTSUPP);
  335 
  336         /* shortcut: check if the name is too long */
  337         if (cnp->cn_namelen >= PFS_NAMELEN)
  338                 PFS_RETURN (ENOENT);
  339 
  340         /* check that parent directory is visisble... */
  341         if (!pfs_visible(curthread, pd, pvd->pvd_pid))
  342                 PFS_RETURN (ENOENT);
  343 
  344         lockparent = cnp->cn_flags & LOCKPARENT;
  345         wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
  346 
  347 
  348         /* self */
  349         namelen = cnp->cn_namelen;
  350         pname = cnp->cn_nameptr;
  351         if (namelen == 1 && *pname == '.') {
  352                 pn = pd;
  353                 *vpp = vn;
  354                 VREF(vn);
  355                 PFS_RETURN (0);
  356         }
  357 
  358         /* parent */
  359         if (cnp->cn_flags & ISDOTDOT) {
  360                 if (pd->pn_type == pfstype_root)
  361                         PFS_RETURN (EIO);
  362                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  363                 cnp->cn_flags |= PDIRUNLOCK;
  364 
  365                 KASSERT(pd->pn_parent, ("non-root directory has no parent"));
  366                 /*
  367                  * This one is tricky.  Descendents of procdir nodes
  368                  * inherit their parent's process affinity, but
  369                  * there's no easy reverse mapping.  For simplicity,
  370                  * we assume that if this node is a procdir, its
  371                  * parent isn't (which is correct as long as
  372                  * descendents of procdir nodes are never procdir
  373                  * nodes themselves)
  374                  */
  375                 if (pd->pn_type == pfstype_procdir)
  376                         pid = NO_PID;
  377                 pn = pd->pn_parent;
  378                 goto got_pnode;
  379         }
  380 
  381         /* named node */
  382         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
  383                 if (pn->pn_type == pfstype_procdir)
  384                         pdn = pn;
  385                 else if (pn->pn_name[namelen] == '\0'
  386                     && bcmp(pname, pn->pn_name, namelen) == 0)
  387                         goto got_pnode;
  388 
  389         /* process dependent node */
  390         if ((pn = pdn) != NULL) {
  391                 pid = 0;
  392                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
  393                         if ((pid = pid * 10 + pname[i] - '') > PID_MAX)
  394                                 break;
  395                 if (i == cnp->cn_namelen)
  396                         goto got_pnode;
  397         }
  398 
  399         PFS_RETURN (ENOENT);
  400  got_pnode:
  401         if (pn != pd->pn_parent && !pn->pn_parent)
  402                 pn->pn_parent = pd;
  403         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  404                 PFS_RETURN (ENOENT);
  405 
  406         error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
  407         if (error)
  408                 PFS_RETURN (error);
  409 
  410         if ((cnp->cn_flags & ISDOTDOT) && (cnp->cn_flags & ISLASTCN)
  411             && lockparent) {
  412                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  413                 cnp->cn_flags &= ~PDIRUNLOCK;
  414         }
  415         if (!lockparent || !(cnp->cn_flags & ISLASTCN))
  416                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  417 
  418         /*
  419          * XXX See comment at top of the routine.
  420          */
  421         if (cnp->cn_flags & MAKEENTRY)
  422                 cache_enter(vn, *vpp, cnp);
  423         PFS_RETURN (0);
  424 }
  425 
  426 /*
  427  * Open a file or directory.
  428  */
  429 static int
  430 pfs_open(struct vop_open_args *va)
  431 {
  432         struct vnode *vn = va->a_vp;
  433         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  434         struct pfs_node *pn = pvd->pvd_pn;
  435         int mode = va->a_mode;
  436 
  437         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
  438 
  439         /*
  440          * check if the file is visible to the caller
  441          *
  442          * XXX Not sure if this is necessary, as the VFS system calls
  443          * XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
  444          * XXX calls pfs_visible().  There's a race condition here, but
  445          * XXX calling pfs_visible() from here doesn't really close it,
  446          * XXX and the only consequence of that race is an EIO further
  447          * XXX down the line.
  448          */
  449         if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
  450                 PFS_RETURN (ENOENT);
  451 
  452         /* check if the requested mode is permitted */
  453         if (((mode & FREAD) && !(mode & PFS_RD)) ||
  454             ((mode & FWRITE) && !(mode & PFS_WR)))
  455                 PFS_RETURN (EPERM);
  456 
  457         /* we don't support locking */
  458         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
  459                 PFS_RETURN (EOPNOTSUPP);
  460 
  461         PFS_RETURN (0);
  462 }
  463 
  464 /*
  465  * Read from a file
  466  */
  467 static int
  468 pfs_read(struct vop_read_args *va)
  469 {
  470         struct vnode *vn = va->a_vp;
  471         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  472         struct pfs_node *pn = pvd->pvd_pn;
  473         struct uio *uio = va->a_uio;
  474         struct proc *proc = NULL;
  475         struct sbuf *sb = NULL;
  476         int error;
  477         unsigned int buflen, offset, resid;
  478 
  479         PFS_TRACE((pn->pn_name));
  480 
  481         if (vn->v_type != VREG)
  482                 PFS_RETURN (EINVAL);
  483 
  484         if (!(pn->pn_flags & PFS_RD))
  485                 PFS_RETURN (EBADF);
  486 
  487         if (pn->pn_func == NULL)
  488                 PFS_RETURN (EIO);
  489 
  490         /*
  491          * This is necessary because either process' privileges may
  492          * have changed since the open() call.
  493          */
  494         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  495                 PFS_RETURN (EIO);
  496 
  497         /* XXX duplicates bits of pfs_visible() */
  498         if (pvd->pvd_pid != NO_PID) {
  499                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  500                         PFS_RETURN (EIO);
  501                 _PHOLD(proc);
  502                 PROC_UNLOCK(proc);
  503         }
  504 
  505         if (pn->pn_flags & PFS_RAWRD) {
  506                 error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
  507                 if (proc != NULL)
  508                         PRELE(proc);
  509                 PFS_RETURN (error);
  510         }
  511 
  512         /* Beaucoup sanity checks so we don't ask for bogus allocation. */
  513         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
  514             (offset = uio->uio_offset) != uio->uio_offset ||
  515             (resid = uio->uio_resid) != uio->uio_resid ||
  516             (buflen = offset + resid) < offset || buflen > INT_MAX) {
  517                 if (proc != NULL)
  518                         PRELE(proc);
  519                 PFS_RETURN (EINVAL);
  520         }
  521         sb = sbuf_new(sb, NULL, buflen, 0);
  522         if (sb == NULL) {
  523                 if (proc != NULL)
  524                         PRELE(proc);
  525                 PFS_RETURN (EIO);
  526         }
  527 
  528         error = (pn->pn_func)(curthread, proc, pn, sb, uio);
  529 
  530         if (proc != NULL)
  531                 PRELE(proc);
  532 
  533         if (error) {
  534                 sbuf_delete(sb);
  535                 PFS_RETURN (error);
  536         }
  537 
  538         sbuf_finish(sb);
  539         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
  540         sbuf_delete(sb);
  541         PFS_RETURN (error);
  542 }
  543 
  544 /*
  545  * Iterate through directory entries
  546  */
  547 static int
  548 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
  549             struct pfs_node **pn, struct proc **p)
  550 {
  551         if ((*pn) == NULL)
  552                 *pn = pd->pn_nodes;
  553         else
  554  again:
  555         if ((*pn)->pn_type != pfstype_procdir)
  556                 *pn = (*pn)->pn_next;
  557 
  558         while (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  559                 if (*p == NULL)
  560                         *p = LIST_FIRST(&allproc);
  561                 else
  562                         *p = LIST_NEXT(*p, p_list);
  563                 if (*p != NULL)
  564                         break;
  565                 *pn = (*pn)->pn_next;
  566         }
  567 
  568         if ((*pn) == NULL)
  569                 return (-1);
  570 
  571         if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
  572                 goto again;
  573 
  574         return (0);
  575 }
  576 
  577 /*
  578  * Return directory entries.
  579  */
  580 static int
  581 pfs_readdir(struct vop_readdir_args *va)
  582 {
  583         struct vnode *vn = va->a_vp;
  584         struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
  585         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  586         struct pfs_node *pd = pvd->pvd_pn;
  587         pid_t pid = pvd->pvd_pid;
  588         struct pfs_node *pn;
  589         struct dirent entry;
  590         struct uio *uio;
  591         struct proc *p;
  592         off_t offset;
  593         int error, i, resid;
  594 
  595         PFS_TRACE((pd->pn_name));
  596 
  597         if (vn->v_type != VDIR)
  598                 PFS_RETURN (ENOTDIR);
  599         uio = va->a_uio;
  600 
  601         /* check if the directory is visible to the caller */
  602         if (!pfs_visible(curthread, pd, pid))
  603                 PFS_RETURN (ENOENT);
  604 
  605         /* only allow reading entire entries */
  606         offset = uio->uio_offset;
  607         resid = uio->uio_resid;
  608         if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
  609                 PFS_RETURN (EINVAL);
  610 
  611         /* skip unwanted entries */
  612         sx_slock(&allproc_lock);
  613         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
  614                 if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
  615                         /* nothing left... */
  616                         sx_sunlock(&allproc_lock);
  617                         PFS_RETURN (0);
  618                 }
  619 
  620         /* fill in entries */
  621         entry.d_reclen = PFS_DELEN;
  622         while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
  623                 if (!pn->pn_parent)
  624                         pn->pn_parent = pd;
  625                 if (!pn->pn_fileno)
  626                         pfs_fileno_alloc(pi, pn);
  627                 if (pid != NO_PID)
  628                         entry.d_fileno = pn->pn_fileno * NO_PID + pid;
  629                 else
  630                         entry.d_fileno = pn->pn_fileno;
  631                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  632                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  633                         entry.d_name[i] = pn->pn_name[i];
  634                 entry.d_name[i] = 0;
  635                 entry.d_namlen = i;
  636                 switch (pn->pn_type) {
  637                 case pfstype_procdir:
  638                         KASSERT(p != NULL,
  639                             ("reached procdir node with p == NULL"));
  640                         entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
  641                         entry.d_namlen = snprintf(entry.d_name,
  642                             PFS_NAMELEN, "%d", p->p_pid);
  643                         /* fall through */
  644                 case pfstype_root:
  645                 case pfstype_dir:
  646                 case pfstype_this:
  647                 case pfstype_parent:
  648                         entry.d_type = DT_DIR;
  649                         break;
  650                 case pfstype_file:
  651                         entry.d_type = DT_REG;
  652                         break;
  653                 case pfstype_symlink:
  654                         entry.d_type = DT_LNK;
  655                         break;
  656                 default:
  657                         sx_sunlock(&allproc_lock);
  658                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  659                 }
  660                 PFS_TRACE((entry.d_name));
  661                 if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) {
  662                         sx_sunlock(&allproc_lock);
  663                         PFS_RETURN (error);
  664                 }
  665                 offset += PFS_DELEN;
  666                 resid -= PFS_DELEN;
  667         }
  668 
  669         sx_sunlock(&allproc_lock);
  670         uio->uio_offset += offset;
  671         PFS_RETURN (0);
  672 }
  673 
  674 /*
  675  * Read a symbolic link
  676  */
  677 static int
  678 pfs_readlink(struct vop_readlink_args *va)
  679 {
  680         struct vnode *vn = va->a_vp;
  681         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  682         struct pfs_node *pn = pvd->pvd_pn;
  683         struct uio *uio = va->a_uio;
  684         struct proc *proc = NULL;
  685         char buf[MAXPATHLEN];
  686         struct sbuf sb;
  687         int error;
  688 
  689         PFS_TRACE((pn->pn_name));
  690 
  691         if (vn->v_type != VLNK)
  692                 PFS_RETURN (EINVAL);
  693 
  694         if (pn->pn_func == NULL)
  695                 PFS_RETURN (EIO);
  696 
  697         if (pvd->pvd_pid != NO_PID) {
  698                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  699                         PFS_RETURN (EIO);
  700                 _PHOLD(proc);
  701                 PROC_UNLOCK(proc);
  702         }
  703 
  704         /* sbuf_new() can't fail with a static buffer */
  705         sbuf_new(&sb, buf, sizeof buf, 0);
  706 
  707         error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
  708 
  709         if (proc != NULL)
  710                 PRELE(proc);
  711 
  712         if (error) {
  713                 sbuf_delete(&sb);
  714                 PFS_RETURN (error);
  715         }
  716 
  717         sbuf_finish(&sb);
  718         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
  719         sbuf_delete(&sb);
  720         PFS_RETURN (error);
  721 }
  722 
  723 /*
  724  * Reclaim a vnode
  725  */
  726 static int
  727 pfs_reclaim(struct vop_reclaim_args *va)
  728 {
  729         PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
  730 
  731         return (pfs_vncache_free(va->a_vp));
  732 }
  733 
  734 /*
  735  * Set attributes
  736  */
  737 static int
  738 pfs_setattr(struct vop_setattr_args *va)
  739 {
  740         PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
  741 
  742         PFS_RETURN (EOPNOTSUPP);
  743 }
  744 
  745 /*
  746  * Read from a file
  747  */
  748 static int
  749 pfs_write(struct vop_read_args *va)
  750 {
  751         struct vnode *vn = va->a_vp;
  752         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  753         struct pfs_node *pn = pvd->pvd_pn;
  754         struct uio *uio = va->a_uio;
  755         struct proc *proc = NULL;
  756         struct sbuf sb;
  757         int error;
  758 
  759         PFS_TRACE((pn->pn_name));
  760 
  761         if (vn->v_type != VREG)
  762                 PFS_RETURN (EINVAL);
  763 
  764         if (!(pn->pn_flags & PFS_WR))
  765                 PFS_RETURN (EBADF);
  766 
  767         if (pn->pn_func == NULL)
  768                 PFS_RETURN (EIO);
  769 
  770         /*
  771          * This is necessary because either process' privileges may
  772          * have changed since the open() call.
  773          */
  774         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  775                 PFS_RETURN (EIO);
  776 
  777         /* XXX duplicates bits of pfs_visible() */
  778         if (pvd->pvd_pid != NO_PID) {
  779                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  780                         PFS_RETURN (EIO);
  781                 _PHOLD(proc);
  782                 PROC_UNLOCK(proc);
  783         }
  784 
  785         if (pn->pn_flags & PFS_RAWWR) {
  786                 error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
  787                 if (proc != NULL)
  788                         PRELE(proc);
  789                 PFS_RETURN (error);
  790         }
  791 
  792         sbuf_uionew(&sb, uio, &error);
  793         if (error)
  794                 PFS_RETURN (error);
  795 
  796         error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
  797 
  798         if (proc != NULL)
  799                 PRELE(proc);
  800 
  801         sbuf_delete(&sb);
  802         PFS_RETURN (error);
  803 }
  804 
  805 /*
  806  * Vnode operations
  807  */
  808 vop_t **pfs_vnodeop_p;
  809 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
  810         { &vop_default_desc,            (vop_t *)vop_defaultop  },
  811         { &vop_access_desc,             (vop_t *)pfs_access     },
  812         { &vop_close_desc,              (vop_t *)pfs_close      },
  813         { &vop_create_desc,             (vop_t *)vop_eopnotsupp },
  814         { &vop_getattr_desc,            (vop_t *)pfs_getattr    },
  815         { &vop_getextattr_desc,         (vop_t *)pfs_getextattr },
  816         { &vop_ioctl_desc,              (vop_t *)pfs_ioctl      },
  817         { &vop_link_desc,               (vop_t *)vop_eopnotsupp },
  818         { &vop_lookup_desc,             (vop_t *)pfs_lookup     },
  819         { &vop_mkdir_desc,              (vop_t *)vop_eopnotsupp },
  820         { &vop_mknod_desc,              (vop_t *)vop_eopnotsupp },
  821         { &vop_open_desc,               (vop_t *)pfs_open       },
  822         { &vop_read_desc,               (vop_t *)pfs_read       },
  823         { &vop_readdir_desc,            (vop_t *)pfs_readdir    },
  824         { &vop_readlink_desc,           (vop_t *)pfs_readlink   },
  825         { &vop_reclaim_desc,            (vop_t *)pfs_reclaim    },
  826 #ifdef MAC
  827         { &vop_refreshlabel_desc,       (vop_t *)pfs_refreshlabel },
  828 #endif
  829         { &vop_remove_desc,             (vop_t *)vop_eopnotsupp },
  830         { &vop_rename_desc,             (vop_t *)vop_eopnotsupp },
  831         { &vop_rmdir_desc,              (vop_t *)vop_eopnotsupp },
  832         { &vop_setattr_desc,            (vop_t *)pfs_setattr    },
  833         { &vop_symlink_desc,            (vop_t *)vop_eopnotsupp },
  834         { &vop_write_desc,              (vop_t *)pfs_write      },
  835         { &vop_lock_desc,               (vop_t *)vop_stdlock    },
  836         { &vop_unlock_desc,             (vop_t *)vop_stdunlock  },
  837         { &vop_islocked_desc,           (vop_t *)vop_stdislocked},
  838         /* XXX I've probably forgotten a few that need vop_eopnotsupp */
  839         { NULL,                         (vop_t *)NULL           }
  840 };
  841 
  842 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
  843         { &pfs_vnodeop_p, pfs_vnodeop_entries };
  844 
  845 VNODEOP_SET(pfs_vnodeop_opv_desc);

Cache object: f97c9aa6a86bba21bb74a02b1bcea8b9


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