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

Cache object: 94c222add2ce16dd9c2c59d0d9ffe98d


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