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.2/sys/fs/pseudofs/pseudofs_vnops.c 125672 2004-02-10 21:08:01Z 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/limits.h>
   38 #include <sys/lock.h>
   39 #include <sys/mount.h>
   40 #include <sys/mutex.h>
   41 #include <sys/namei.h>
   42 #include <sys/proc.h>
   43 #include <sys/sbuf.h>
   44 #include <sys/sx.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/vnode.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         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  168                 PFS_RETURN (ENOENT);
  169 
  170         VATTR_NULL(vap);
  171         vap->va_type = vn->v_type;
  172         vap->va_fileid = pn->pn_fileno;
  173         vap->va_flags = 0;
  174         vap->va_blocksize = PAGE_SIZE;
  175         vap->va_bytes = vap->va_size = 0;
  176         vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
  177         vap->va_nlink = 1;
  178         nanotime(&vap->va_ctime);
  179         vap->va_atime = vap->va_mtime = vap->va_ctime;
  180 
  181         switch (pn->pn_type) {
  182         case pfstype_procdir:
  183         case pfstype_root:
  184         case pfstype_dir:
  185                 vap->va_mode = 0555;
  186                 break;
  187         case pfstype_file:
  188         case pfstype_symlink:
  189                 vap->va_mode = 0444;
  190                 break;
  191         default:
  192                 printf("shouldn't be here!\n");
  193                 vap->va_mode = 0;
  194                 break;
  195         }
  196 
  197         if (pvd->pvd_pid != NO_PID) {
  198                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  199                         PFS_RETURN (ENOENT);
  200                 vap->va_uid = proc->p_ucred->cr_ruid;
  201                 vap->va_gid = proc->p_ucred->cr_rgid;
  202                 if (pn->pn_attr != NULL)
  203                         error = (pn->pn_attr)(va->a_td, proc, pn, vap);
  204                 PROC_UNLOCK(proc);
  205         } else {
  206                 vap->va_uid = 0;
  207                 vap->va_gid = 0;
  208         }
  209 
  210         PFS_RETURN (error);
  211 }
  212 
  213 /*
  214  * Perform an ioctl
  215  */
  216 static int
  217 pfs_ioctl(struct vop_ioctl_args *va)
  218 {
  219         struct vnode *vn = va->a_vp;
  220         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  221         struct pfs_node *pn = pvd->pvd_pn;
  222         struct proc *proc = NULL;
  223         int error;
  224 
  225         PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
  226 
  227         if (vn->v_type != VREG)
  228                 PFS_RETURN (EINVAL);
  229 
  230         if (pn->pn_ioctl == NULL)
  231                 PFS_RETURN (ENOTTY);
  232 
  233         /*
  234          * This is necessary because process' privileges may
  235          * have changed since the open() call.
  236          */
  237         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  238                 PFS_RETURN (EIO);
  239 
  240         /* XXX duplicates bits of pfs_visible() */
  241         if (pvd->pvd_pid != NO_PID) {
  242                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  243                         PFS_RETURN (EIO);
  244                 _PHOLD(proc);
  245                 PROC_UNLOCK(proc);
  246         }
  247 
  248         error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data);
  249 
  250         if (proc != NULL)
  251                 PRELE(proc);
  252 
  253         PFS_RETURN (error);
  254 }
  255 
  256 /*
  257  * Perform getextattr
  258  */
  259 static int
  260 pfs_getextattr(struct vop_getextattr_args *va)
  261 {
  262         struct vnode *vn = va->a_vp;
  263         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  264         struct pfs_node *pn = pvd->pvd_pn;
  265         struct proc *proc = NULL;
  266         int error;
  267 
  268         PFS_TRACE((pd->pn_name));
  269 
  270         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  271                 PFS_RETURN (ENOENT);
  272 
  273         if (pn->pn_getextattr == NULL)
  274                 PFS_RETURN (EOPNOTSUPP);
  275 
  276         /*
  277          * This is necessary because either process' privileges may
  278          * have changed since the open() call.
  279          */
  280         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  281                 PFS_RETURN (EIO);
  282 
  283         /* XXX duplicates bits of pfs_visible() */
  284         if (pvd->pvd_pid != NO_PID) {
  285                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  286                         PFS_RETURN (EIO);
  287                 _PHOLD(proc);
  288                 PROC_UNLOCK(proc);
  289         }
  290 
  291         error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
  292             va->a_name, va->a_uio, va->a_size, va->a_cred);
  293 
  294         if (proc != NULL)
  295                 PRELE(proc);
  296 
  297         PFS_RETURN (error);
  298 }
  299 
  300 /*
  301  * Look up a file or directory
  302  *
  303  * XXX NOTE!  pfs_lookup() has been hooked into vop_lookup_desc!  This
  304  * will result in a lookup operation for a vnode which may already be
  305  * cached, therefore we have to be careful to purge the VFS cache when
  306  * reusing a vnode.
  307  *
  308  * This code will work, but is not really correct.  Normally we would hook
  309  * vfs_cache_lookup() into vop_lookup_desc and hook pfs_lookup() into
  310  * vop_cachedlookup_desc.
  311  */
  312 static int
  313 pfs_lookup(struct vop_lookup_args *va)
  314 {
  315         struct vnode *vn = va->a_dvp;
  316         struct vnode **vpp = va->a_vpp;
  317         struct componentname *cnp = va->a_cnp;
  318         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  319         struct pfs_node *pd = pvd->pvd_pn;
  320         struct pfs_node *pn, *pdn = NULL;
  321         pid_t pid = pvd->pvd_pid;
  322         int lockparent;
  323         int wantparent;
  324         char *pname;
  325         int error, i, namelen;
  326 
  327         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
  328 
  329         cnp->cn_flags &= ~PDIRUNLOCK;
  330 
  331         if (vn->v_type != VDIR)
  332                 PFS_RETURN (ENOTDIR);
  333 
  334         /*
  335          * Don't support DELETE or RENAME.  CREATE is supported so
  336          * that O_CREAT will work, but the lookup will still fail if
  337          * the file does not exist.
  338          */
  339         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  340                 PFS_RETURN (EOPNOTSUPP);
  341 
  342         /* shortcut: check if the name is too long */
  343         if (cnp->cn_namelen >= PFS_NAMELEN)
  344                 PFS_RETURN (ENOENT);
  345 
  346         /* check that parent directory is visisble... */
  347         if (!pfs_visible(curthread, pd, pvd->pvd_pid))
  348                 PFS_RETURN (ENOENT);
  349 
  350         lockparent = cnp->cn_flags & LOCKPARENT;
  351         wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
  352 
  353 
  354         /* self */
  355         namelen = cnp->cn_namelen;
  356         pname = cnp->cn_nameptr;
  357         if (namelen == 1 && *pname == '.') {
  358                 pn = pd;
  359                 *vpp = vn;
  360                 VREF(vn);
  361                 PFS_RETURN (0);
  362         }
  363 
  364         /* parent */
  365         if (cnp->cn_flags & ISDOTDOT) {
  366                 if (pd->pn_type == pfstype_root)
  367                         PFS_RETURN (EIO);
  368                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  369                 cnp->cn_flags |= PDIRUNLOCK;
  370 
  371                 KASSERT(pd->pn_parent, ("non-root directory has no parent"));
  372                 /*
  373                  * This one is tricky.  Descendents of procdir nodes
  374                  * inherit their parent's process affinity, but
  375                  * there's no easy reverse mapping.  For simplicity,
  376                  * we assume that if this node is a procdir, its
  377                  * parent isn't (which is correct as long as
  378                  * descendents of procdir nodes are never procdir
  379                  * nodes themselves)
  380                  */
  381                 if (pd->pn_type == pfstype_procdir)
  382                         pid = NO_PID;
  383                 pn = pd->pn_parent;
  384                 goto got_pnode;
  385         }
  386 
  387         /* named node */
  388         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
  389                 if (pn->pn_type == pfstype_procdir)
  390                         pdn = pn;
  391                 else if (pn->pn_name[namelen] == '\0'
  392                     && bcmp(pname, pn->pn_name, namelen) == 0)
  393                         goto got_pnode;
  394 
  395         /* process dependent node */
  396         if ((pn = pdn) != NULL) {
  397                 pid = 0;
  398                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
  399                         if ((pid = pid * 10 + pname[i] - '') > PID_MAX)
  400                                 break;
  401                 if (i == cnp->cn_namelen)
  402                         goto got_pnode;
  403         }
  404 
  405         PFS_RETURN (ENOENT);
  406  got_pnode:
  407         if (pn != pd->pn_parent && !pn->pn_parent)
  408                 pn->pn_parent = pd;
  409         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  410                 PFS_RETURN (ENOENT);
  411 
  412         error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
  413         if (error)
  414                 PFS_RETURN (error);
  415 
  416         if ((cnp->cn_flags & ISDOTDOT) && (cnp->cn_flags & ISLASTCN)
  417             && lockparent) {
  418                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  419                 cnp->cn_flags &= ~PDIRUNLOCK;
  420         }
  421         if (!((lockparent && (cnp->cn_flags & ISLASTCN)) ||
  422             (cnp->cn_flags & ISDOTDOT)))
  423                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  424 
  425         /*
  426          * XXX See comment at top of the routine.
  427          */
  428         if (cnp->cn_flags & MAKEENTRY)
  429                 cache_enter(vn, *vpp, cnp);
  430         PFS_RETURN (0);
  431 }
  432 
  433 /*
  434  * Open a file or directory.
  435  */
  436 static int
  437 pfs_open(struct vop_open_args *va)
  438 {
  439         struct vnode *vn = va->a_vp;
  440         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  441         struct pfs_node *pn = pvd->pvd_pn;
  442         int mode = va->a_mode;
  443 
  444         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
  445 
  446         /*
  447          * check if the file is visible to the caller
  448          *
  449          * XXX Not sure if this is necessary, as the VFS system calls
  450          * XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
  451          * XXX calls pfs_visible().  There's a race condition here, but
  452          * XXX calling pfs_visible() from here doesn't really close it,
  453          * XXX and the only consequence of that race is an EIO further
  454          * XXX down the line.
  455          */
  456         if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
  457                 PFS_RETURN (ENOENT);
  458 
  459         /* check if the requested mode is permitted */
  460         if (((mode & FREAD) && !(mode & PFS_RD)) ||
  461             ((mode & FWRITE) && !(mode & PFS_WR)))
  462                 PFS_RETURN (EPERM);
  463 
  464         /* we don't support locking */
  465         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
  466                 PFS_RETURN (EOPNOTSUPP);
  467 
  468         PFS_RETURN (0);
  469 }
  470 
  471 /*
  472  * Read from a file
  473  */
  474 static int
  475 pfs_read(struct vop_read_args *va)
  476 {
  477         struct vnode *vn = va->a_vp;
  478         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  479         struct pfs_node *pn = pvd->pvd_pn;
  480         struct uio *uio = va->a_uio;
  481         struct proc *proc = NULL;
  482         struct sbuf *sb = NULL;
  483         int error;
  484         unsigned int buflen, offset, resid;
  485 
  486         PFS_TRACE((pn->pn_name));
  487 
  488         if (vn->v_type != VREG)
  489                 PFS_RETURN (EINVAL);
  490 
  491         if (!(pn->pn_flags & PFS_RD))
  492                 PFS_RETURN (EBADF);
  493 
  494         if (pn->pn_func == NULL)
  495                 PFS_RETURN (EIO);
  496 
  497         /*
  498          * This is necessary because either process' privileges may
  499          * have changed since the open() call.
  500          */
  501         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  502                 PFS_RETURN (EIO);
  503 
  504         /* XXX duplicates bits of pfs_visible() */
  505         if (pvd->pvd_pid != NO_PID) {
  506                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  507                         PFS_RETURN (EIO);
  508                 _PHOLD(proc);
  509                 PROC_UNLOCK(proc);
  510         }
  511 
  512         if (pn->pn_flags & PFS_RAWRD) {
  513                 error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
  514                 if (proc != NULL)
  515                         PRELE(proc);
  516                 PFS_RETURN (error);
  517         }
  518 
  519         /* Beaucoup sanity checks so we don't ask for bogus allocation. */
  520         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
  521             (offset = uio->uio_offset) != uio->uio_offset ||
  522             (resid = uio->uio_resid) != uio->uio_resid ||
  523             (buflen = offset + resid) < offset || buflen > INT_MAX) {
  524                 if (proc != NULL)
  525                         PRELE(proc);
  526                 PFS_RETURN (EINVAL);
  527         }
  528         if (buflen > MAXPHYS) {
  529                 if (proc != NULL)
  530                         PRELE(proc);
  531                 PFS_RETURN (EIO);
  532         }
  533         sb = sbuf_new(sb, NULL, buflen, 0);
  534         if (sb == NULL) {
  535                 if (proc != NULL)
  536                         PRELE(proc);
  537                 PFS_RETURN (EIO);
  538         }
  539 
  540         error = (pn->pn_func)(curthread, proc, pn, sb, uio);
  541 
  542         if (proc != NULL)
  543                 PRELE(proc);
  544 
  545         if (error) {
  546                 sbuf_delete(sb);
  547                 PFS_RETURN (error);
  548         }
  549 
  550         sbuf_finish(sb);
  551         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
  552         sbuf_delete(sb);
  553         PFS_RETURN (error);
  554 }
  555 
  556 /*
  557  * Iterate through directory entries
  558  */
  559 static int
  560 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
  561             struct pfs_node **pn, struct proc **p)
  562 {
  563         sx_assert(&allproc_lock, SX_LOCKED);
  564  again:
  565         if (*pn == NULL) {
  566                 /* first node */
  567                 *pn = pd->pn_nodes;
  568         } else if ((*pn)->pn_type != pfstype_procdir) {
  569                 /* next node */
  570                 *pn = (*pn)->pn_next;
  571         }
  572         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  573                 /* next process */
  574                 if (*p == NULL)
  575                         *p = LIST_FIRST(&allproc);
  576                 else
  577                         *p = LIST_NEXT(*p, p_list);
  578                 /* out of processes: next node */
  579                 if (*p == NULL)
  580                         *pn = (*pn)->pn_next;
  581         }
  582 
  583         if ((*pn) == NULL)
  584                 return (-1);
  585 
  586         if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
  587                 goto again;
  588 
  589         return (0);
  590 }
  591 
  592 /*
  593  * Return directory entries.
  594  */
  595 static int
  596 pfs_readdir(struct vop_readdir_args *va)
  597 {
  598         struct vnode *vn = va->a_vp;
  599         struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
  600         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  601         struct pfs_node *pd = pvd->pvd_pn;
  602         pid_t pid = pvd->pvd_pid;
  603         struct pfs_node *pn;
  604         struct dirent entry;
  605         struct uio *uio;
  606         struct proc *p;
  607         off_t offset;
  608         int error, i, resid;
  609 
  610         PFS_TRACE((pd->pn_name));
  611 
  612         if (vn->v_type != VDIR)
  613                 PFS_RETURN (ENOTDIR);
  614         uio = va->a_uio;
  615 
  616         /* check if the directory is visible to the caller */
  617         if (!pfs_visible(curthread, pd, pid))
  618                 PFS_RETURN (ENOENT);
  619 
  620         /* only allow reading entire entries */
  621         offset = uio->uio_offset;
  622         resid = uio->uio_resid;
  623         if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
  624                 PFS_RETURN (EINVAL);
  625 
  626         /* skip unwanted entries */
  627         sx_slock(&allproc_lock);
  628         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
  629                 if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
  630                         /* nothing left... */
  631                         sx_sunlock(&allproc_lock);
  632                         PFS_RETURN (0);
  633                 }
  634 
  635         /* fill in entries */
  636         entry.d_reclen = PFS_DELEN;
  637         while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
  638                 if (!pn->pn_parent)
  639                         pn->pn_parent = pd;
  640                 if (!pn->pn_fileno)
  641                         pfs_fileno_alloc(pi, pn);
  642                 if (pid != NO_PID)
  643                         entry.d_fileno = pn->pn_fileno * NO_PID + pid;
  644                 else
  645                         entry.d_fileno = pn->pn_fileno;
  646                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  647                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  648                         entry.d_name[i] = pn->pn_name[i];
  649                 entry.d_name[i] = 0;
  650                 entry.d_namlen = i;
  651                 switch (pn->pn_type) {
  652                 case pfstype_procdir:
  653                         KASSERT(p != NULL,
  654                             ("reached procdir node with p == NULL"));
  655                         entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
  656                         entry.d_namlen = snprintf(entry.d_name,
  657                             PFS_NAMELEN, "%d", p->p_pid);
  658                         /* fall through */
  659                 case pfstype_root:
  660                 case pfstype_dir:
  661                 case pfstype_this:
  662                 case pfstype_parent:
  663                         entry.d_type = DT_DIR;
  664                         break;
  665                 case pfstype_file:
  666                         entry.d_type = DT_REG;
  667                         break;
  668                 case pfstype_symlink:
  669                         entry.d_type = DT_LNK;
  670                         break;
  671                 default:
  672                         sx_sunlock(&allproc_lock);
  673                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  674                 }
  675                 PFS_TRACE((entry.d_name));
  676                 if ((error = uiomove(&entry, PFS_DELEN, uio))) {
  677                         sx_sunlock(&allproc_lock);
  678                         PFS_RETURN (error);
  679                 }
  680                 offset += PFS_DELEN;
  681                 resid -= PFS_DELEN;
  682         }
  683 
  684         sx_sunlock(&allproc_lock);
  685         uio->uio_offset += offset;
  686         PFS_RETURN (0);
  687 }
  688 
  689 /*
  690  * Read a symbolic link
  691  */
  692 static int
  693 pfs_readlink(struct vop_readlink_args *va)
  694 {
  695         struct vnode *vn = va->a_vp;
  696         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  697         struct pfs_node *pn = pvd->pvd_pn;
  698         struct uio *uio = va->a_uio;
  699         struct proc *proc = NULL;
  700         char buf[MAXPATHLEN];
  701         struct sbuf sb;
  702         int error;
  703 
  704         PFS_TRACE((pn->pn_name));
  705 
  706         if (vn->v_type != VLNK)
  707                 PFS_RETURN (EINVAL);
  708 
  709         if (pn->pn_func == NULL)
  710                 PFS_RETURN (EIO);
  711 
  712         if (pvd->pvd_pid != NO_PID) {
  713                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  714                         PFS_RETURN (EIO);
  715                 _PHOLD(proc);
  716                 PROC_UNLOCK(proc);
  717         }
  718 
  719         /* sbuf_new() can't fail with a static buffer */
  720         sbuf_new(&sb, buf, sizeof buf, 0);
  721 
  722         error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
  723 
  724         if (proc != NULL)
  725                 PRELE(proc);
  726 
  727         if (error) {
  728                 sbuf_delete(&sb);
  729                 PFS_RETURN (error);
  730         }
  731 
  732         sbuf_finish(&sb);
  733         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
  734         sbuf_delete(&sb);
  735         PFS_RETURN (error);
  736 }
  737 
  738 /*
  739  * Reclaim a vnode
  740  */
  741 static int
  742 pfs_reclaim(struct vop_reclaim_args *va)
  743 {
  744         PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
  745 
  746         return (pfs_vncache_free(va->a_vp));
  747 }
  748 
  749 /*
  750  * Set attributes
  751  */
  752 static int
  753 pfs_setattr(struct vop_setattr_args *va)
  754 {
  755         PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
  756 
  757         PFS_RETURN (EOPNOTSUPP);
  758 }
  759 
  760 /*
  761  * Read from a file
  762  */
  763 static int
  764 pfs_write(struct vop_read_args *va)
  765 {
  766         struct vnode *vn = va->a_vp;
  767         struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
  768         struct pfs_node *pn = pvd->pvd_pn;
  769         struct uio *uio = va->a_uio;
  770         struct proc *proc = NULL;
  771         struct sbuf sb;
  772         int error;
  773 
  774         PFS_TRACE((pn->pn_name));
  775 
  776         if (vn->v_type != VREG)
  777                 PFS_RETURN (EINVAL);
  778 
  779         if (!(pn->pn_flags & PFS_WR))
  780                 PFS_RETURN (EBADF);
  781 
  782         if (pn->pn_func == NULL)
  783                 PFS_RETURN (EIO);
  784 
  785         /*
  786          * This is necessary because either process' privileges may
  787          * have changed since the open() call.
  788          */
  789         if (!pfs_visible(curthread, pn, pvd->pvd_pid))
  790                 PFS_RETURN (EIO);
  791 
  792         /* XXX duplicates bits of pfs_visible() */
  793         if (pvd->pvd_pid != NO_PID) {
  794                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  795                         PFS_RETURN (EIO);
  796                 _PHOLD(proc);
  797                 PROC_UNLOCK(proc);
  798         }
  799 
  800         if (pn->pn_flags & PFS_RAWWR) {
  801                 error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
  802                 if (proc != NULL)
  803                         PRELE(proc);
  804                 PFS_RETURN (error);
  805         }
  806 
  807         sbuf_uionew(&sb, uio, &error);
  808         if (error)
  809                 PFS_RETURN (error);
  810 
  811         error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
  812 
  813         if (proc != NULL)
  814                 PRELE(proc);
  815 
  816         sbuf_delete(&sb);
  817         PFS_RETURN (error);
  818 }
  819 
  820 /*
  821  * Vnode operations
  822  */
  823 vop_t **pfs_vnodeop_p;
  824 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
  825         { &vop_default_desc,            (vop_t *)vop_defaultop  },
  826         { &vop_access_desc,             (vop_t *)pfs_access     },
  827         { &vop_close_desc,              (vop_t *)pfs_close      },
  828         { &vop_create_desc,             (vop_t *)vop_eopnotsupp },
  829         { &vop_getattr_desc,            (vop_t *)pfs_getattr    },
  830         { &vop_getextattr_desc,         (vop_t *)pfs_getextattr },
  831         { &vop_ioctl_desc,              (vop_t *)pfs_ioctl      },
  832         { &vop_link_desc,               (vop_t *)vop_eopnotsupp },
  833         { &vop_lookup_desc,             (vop_t *)pfs_lookup     },
  834         { &vop_mkdir_desc,              (vop_t *)vop_eopnotsupp },
  835         { &vop_mknod_desc,              (vop_t *)vop_eopnotsupp },
  836         { &vop_open_desc,               (vop_t *)pfs_open       },
  837         { &vop_read_desc,               (vop_t *)pfs_read       },
  838         { &vop_readdir_desc,            (vop_t *)pfs_readdir    },
  839         { &vop_readlink_desc,           (vop_t *)pfs_readlink   },
  840         { &vop_reclaim_desc,            (vop_t *)pfs_reclaim    },
  841         { &vop_remove_desc,             (vop_t *)vop_eopnotsupp },
  842         { &vop_rename_desc,             (vop_t *)vop_eopnotsupp },
  843         { &vop_rmdir_desc,              (vop_t *)vop_eopnotsupp },
  844         { &vop_setattr_desc,            (vop_t *)pfs_setattr    },
  845         { &vop_symlink_desc,            (vop_t *)vop_eopnotsupp },
  846         { &vop_write_desc,              (vop_t *)pfs_write      },
  847         /* XXX I've probably forgotten a few that need vop_eopnotsupp */
  848         { NULL,                         (vop_t *)NULL           }
  849 };
  850 
  851 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
  852         { &pfs_vnodeop_p, pfs_vnodeop_entries };
  853 
  854 VNODEOP_SET(pfs_vnodeop_opv_desc);

Cache object: 059f2e566e0022525700c75af955e096


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