2001-04-07 19:51:12 +00:00
|
|
|
|
/*-
|
|
|
|
|
* Copyright (c) 2001 Dag-Erling Co<EFBFBD>dan Sm<EFBFBD>rgrav
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
|
* are met:
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer
|
|
|
|
|
* in this position and unchanged.
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
2005-03-14 15:54:11 +00:00
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
|
|
#include "opt_pseudofs.h"
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
|
#include <sys/systm.h>
|
|
|
|
|
#include <sys/ctype.h>
|
|
|
|
|
#include <sys/dirent.h>
|
2001-09-30 19:41:29 +00:00
|
|
|
|
#include <sys/fcntl.h>
|
2003-10-02 15:00:55 +00:00
|
|
|
|
#include <sys/limits.h>
|
2001-06-11 15:04:48 +00:00
|
|
|
|
#include <sys/lock.h>
|
2005-03-14 16:21:32 +00:00
|
|
|
|
#include <sys/malloc.h>
|
2001-04-07 19:51:12 +00:00
|
|
|
|
#include <sys/mount.h>
|
2001-06-10 10:42:55 +00:00
|
|
|
|
#include <sys/mutex.h>
|
2001-04-07 19:51:12 +00:00
|
|
|
|
#include <sys/namei.h>
|
|
|
|
|
#include <sys/proc.h>
|
|
|
|
|
#include <sys/sbuf.h>
|
|
|
|
|
#include <sys/sx.h>
|
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
|
|
|
|
|
|
#include <fs/pseudofs/pseudofs.h>
|
|
|
|
|
#include <fs/pseudofs/pseudofs_internal.h>
|
|
|
|
|
|
2005-03-14 16:06:47 +00:00
|
|
|
|
#ifdef PSEUDOFS_TRACE
|
|
|
|
|
static int pfs_trace;
|
|
|
|
|
SYSCTL_INT(_vfs_pfs, OID_AUTO, trace, CTLFLAG_RW, &pfs_trace, 0,
|
|
|
|
|
"enable tracing of pseudofs vnode operations");
|
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
#define PFS_TRACE(foo) \
|
|
|
|
|
do { \
|
2005-03-14 16:06:47 +00:00
|
|
|
|
if (pfs_trace) { \
|
|
|
|
|
printf("%s(): line %d: ", __func__, __LINE__); \
|
|
|
|
|
printf foo ; \
|
|
|
|
|
printf("\n"); \
|
|
|
|
|
} \
|
2001-09-29 00:49:29 +00:00
|
|
|
|
} while (0)
|
|
|
|
|
#define PFS_RETURN(err) \
|
|
|
|
|
do { \
|
2005-03-14 16:06:47 +00:00
|
|
|
|
if (pfs_trace) { \
|
|
|
|
|
printf("%s(): line %d: returning %d\n", \
|
|
|
|
|
__func__, __LINE__, err); \
|
|
|
|
|
} \
|
2001-09-29 00:49:29 +00:00
|
|
|
|
return (err); \
|
|
|
|
|
} while (0)
|
|
|
|
|
#else
|
|
|
|
|
#define PFS_TRACE(foo) \
|
|
|
|
|
do { /* nothing */ } while (0)
|
|
|
|
|
#define PFS_RETURN(err) \
|
|
|
|
|
return (err)
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* Returns non-zero if given file is visible to given process
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid)
|
|
|
|
|
{
|
|
|
|
|
struct proc *proc;
|
|
|
|
|
int r;
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_TRACE(("%s (pid: %d, req: %d)",
|
|
|
|
|
pn->pn_name, pid, td->td_proc->p_pid));
|
2001-10-02 22:22:42 +00:00
|
|
|
|
|
|
|
|
|
if (pn->pn_flags & PFS_DISABLED)
|
|
|
|
|
PFS_RETURN (0);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
r = 1;
|
2001-10-02 22:22:42 +00:00
|
|
|
|
if (pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pid)) == NULL)
|
|
|
|
|
PFS_RETURN (0);
|
2002-05-19 00:14:50 +00:00
|
|
|
|
if (p_cansee(td, proc) != 0 ||
|
2001-10-02 22:22:42 +00:00
|
|
|
|
(pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn)))
|
|
|
|
|
r = 0;
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_RETURN (r);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Verify permissions
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_access(struct vop_access_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct vattr vattr;
|
|
|
|
|
int error;
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-19 01:43:06 +00:00
|
|
|
|
PFS_TRACE((((struct pfs_vdata *)vn->v_data)->pvd_pn->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
|
error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (error)
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
|
|
|
|
|
vattr.va_gid, va->a_mode, va->a_cred, NULL);
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Close a file or directory
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_close(struct vop_close_args *va)
|
|
|
|
|
{
|
2001-11-27 13:26:27 +00:00
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
|
|
|
|
struct proc *proc;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
PFS_TRACE((pn->pn_name));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do nothing unless this is the last close and the node has a
|
|
|
|
|
* last-close handler.
|
|
|
|
|
*/
|
2002-09-25 02:32:42 +00:00
|
|
|
|
if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
|
2001-11-27 13:26:27 +00:00
|
|
|
|
PFS_RETURN (0);
|
|
|
|
|
|
|
|
|
|
if (pvd->pvd_pid != NO_PID)
|
|
|
|
|
proc = pfind(pvd->pvd_pid);
|
|
|
|
|
else
|
|
|
|
|
proc = NULL;
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-11-27 13:26:27 +00:00
|
|
|
|
error = (pn->pn_close)(va->a_td, proc, pn);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-11-27 13:26:27 +00:00
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PROC_UNLOCK(proc);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-11-27 13:26:27 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get file attributes
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_getattr(struct vop_getattr_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct vattr *vap = va->a_vap;
|
2001-09-29 00:49:29 +00:00
|
|
|
|
struct proc *proc;
|
|
|
|
|
int error = 0;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE((pn->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2003-08-19 10:26:41 +00:00
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (ENOENT);
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
VATTR_NULL(vap);
|
|
|
|
|
vap->va_type = vn->v_type;
|
|
|
|
|
vap->va_fileid = pn->pn_fileno;
|
|
|
|
|
vap->va_flags = 0;
|
|
|
|
|
vap->va_blocksize = PAGE_SIZE;
|
|
|
|
|
vap->va_bytes = vap->va_size = 0;
|
|
|
|
|
vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
|
|
|
|
|
vap->va_nlink = 1;
|
|
|
|
|
nanotime(&vap->va_ctime);
|
|
|
|
|
vap->va_atime = vap->va_mtime = vap->va_ctime;
|
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
switch (pn->pn_type) {
|
|
|
|
|
case pfstype_procdir:
|
|
|
|
|
case pfstype_root:
|
|
|
|
|
case pfstype_dir:
|
|
|
|
|
vap->va_mode = 0555;
|
|
|
|
|
break;
|
|
|
|
|
case pfstype_file:
|
|
|
|
|
case pfstype_symlink:
|
2001-09-30 19:41:29 +00:00
|
|
|
|
vap->va_mode = 0444;
|
2001-09-29 00:49:29 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("shouldn't be here!\n");
|
|
|
|
|
vap->va_mode = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
|
|
|
|
PFS_RETURN (ENOENT);
|
|
|
|
|
vap->va_uid = proc->p_ucred->cr_ruid;
|
|
|
|
|
vap->va_gid = proc->p_ucred->cr_rgid;
|
|
|
|
|
if (pn->pn_attr != NULL)
|
2001-10-01 04:22:20 +00:00
|
|
|
|
error = (pn->pn_attr)(va->a_td, proc, pn, vap);
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
} else {
|
|
|
|
|
vap->va_uid = 0;
|
|
|
|
|
vap->va_gid = 0;
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
/*
|
|
|
|
|
* Perform an ioctl
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_ioctl(struct vop_ioctl_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
|
|
|
|
struct proc *proc = NULL;
|
|
|
|
|
int error;
|
|
|
|
|
|
2001-12-09 00:28:12 +00:00
|
|
|
|
PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
if (vn->v_type != VREG)
|
|
|
|
|
PFS_RETURN (EINVAL);
|
|
|
|
|
|
|
|
|
|
if (pn->pn_ioctl == NULL)
|
|
|
|
|
PFS_RETURN (ENOTTY);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
/*
|
2003-06-20 23:29:04 +00:00
|
|
|
|
* This is necessary because process' privileges may
|
2001-10-26 18:52:47 +00:00
|
|
|
|
* have changed since the open() call.
|
|
|
|
|
*/
|
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
/* XXX duplicates bits of pfs_visible() */
|
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
|
|
|
|
PFS_RETURN (EIO);
|
|
|
|
|
_PHOLD(proc);
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data);
|
|
|
|
|
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-26 18:52:47 +00:00
|
|
|
|
PFS_RETURN (error);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* Perform getextattr
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_getextattr(struct vop_getextattr_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
|
|
|
|
struct proc *proc = NULL;
|
|
|
|
|
int error;
|
|
|
|
|
|
2004-12-06 20:07:17 +00:00
|
|
|
|
PFS_TRACE((pn->pn_name));
|
2001-12-11 20:48:20 +00:00
|
|
|
|
|
2003-08-19 10:26:41 +00:00
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (ENOENT);
|
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
if (pn->pn_getextattr == NULL)
|
|
|
|
|
PFS_RETURN (EOPNOTSUPP);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* This is necessary because either process' privileges may
|
|
|
|
|
* have changed since the open() call.
|
|
|
|
|
*/
|
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
/* XXX duplicates bits of pfs_visible() */
|
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
|
|
|
|
PFS_RETURN (EIO);
|
|
|
|
|
_PHOLD(proc);
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
|
Part I: Update extended attribute API and ABI:
o Modify the system call syntax for extattr_{get,set}_{fd,file}() so
as not to use the scatter gather API (which appeared not to be used
by any consumers, and be less portable), rather, accepts 'data'
and 'nbytes' in the style of other simple read/write interfaces.
This changes the API and ABI.
o Modify system call semantics so that extattr_get_{fd,file}() return
a size_t. When performing a read, the number of bytes read will
be returned, unless the data pointer is NULL, in which case the
number of bytes of data are returned. This changes the API only.
o Modify the VOP_GETEXTATTR() vnode operation to accept a *size_t
argument so as to return the size, if desirable. If set to NULL,
the size will not be returned.
o Update various filesystems (pseodofs, ufs) to DTRT.
These changes should make extended attributes more useful and more
portable. More commits to rebuild the system call files, as well
as update userland utilities to follow.
Obtained from: TrustedBSD Project
Sponsored by: DARPA, NAI Labs
2002-02-10 04:43:22 +00:00
|
|
|
|
va->a_name, va->a_uio, va->a_size, va->a_cred);
|
2001-12-11 20:48:20 +00:00
|
|
|
|
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-12-11 20:48:20 +00:00
|
|
|
|
PFS_RETURN (error);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Look up a file or directory
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2005-03-14 16:24:50 +00:00
|
|
|
|
pfs_lookup(struct vop_cachedlookup_args *va)
|
2001-04-07 19:51:12 +00:00
|
|
|
|
{
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct vnode *vn = va->a_dvp;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct vnode **vpp = va->a_vpp;
|
|
|
|
|
struct componentname *cnp = va->a_cnp;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pd = pvd->pvd_pn;
|
|
|
|
|
struct pfs_node *pn, *pdn = NULL;
|
|
|
|
|
pid_t pid = pvd->pvd_pid;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
char *pname;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
int error, i, namelen;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (vn->v_type != VDIR)
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_RETURN (ENOTDIR);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2005-03-14 16:24:50 +00:00
|
|
|
|
error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
|
|
|
|
|
if (error)
|
|
|
|
|
PFS_RETURN (error);
|
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* Don't support DELETE or RENAME. CREATE is supported so
|
|
|
|
|
* that O_CREAT will work, but the lookup will still fail if
|
|
|
|
|
* the file does not exist.
|
|
|
|
|
*/
|
2005-03-14 16:24:50 +00:00
|
|
|
|
if ((cnp->cn_flags & ISLASTCN) &&
|
|
|
|
|
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EOPNOTSUPP);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
/* shortcut: check if the name is too long */
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (cnp->cn_namelen >= PFS_NAMELEN)
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_RETURN (ENOENT);
|
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/* check that parent directory is visisble... */
|
|
|
|
|
if (!pfs_visible(curthread, pd, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (ENOENT);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* self */
|
2001-06-10 18:39:21 +00:00
|
|
|
|
namelen = cnp->cn_namelen;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
pname = cnp->cn_nameptr;
|
2005-03-14 16:24:50 +00:00
|
|
|
|
if (namelen == 1 && pname[0] == '.') {
|
2001-04-07 19:51:12 +00:00
|
|
|
|
pn = pd;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
*vpp = vn;
|
|
|
|
|
VREF(vn);
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_RETURN (0);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* parent */
|
|
|
|
|
if (cnp->cn_flags & ISDOTDOT) {
|
|
|
|
|
if (pd->pn_type == pfstype_root)
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2002-07-08 01:50:14 +00:00
|
|
|
|
VOP_UNLOCK(vn, 0, cnp->cn_thread);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
KASSERT(pd->pn_parent, ("non-root directory has no parent"));
|
2001-06-10 18:39:21 +00:00
|
|
|
|
/*
|
|
|
|
|
* This one is tricky. Descendents of procdir nodes
|
|
|
|
|
* inherit their parent's process affinity, but
|
|
|
|
|
* there's no easy reverse mapping. For simplicity,
|
|
|
|
|
* we assume that if this node is a procdir, its
|
|
|
|
|
* parent isn't (which is correct as long as
|
|
|
|
|
* descendents of procdir nodes are never procdir
|
|
|
|
|
* nodes themselves)
|
|
|
|
|
*/
|
|
|
|
|
if (pd->pn_type == pfstype_procdir)
|
|
|
|
|
pid = NO_PID;
|
2001-10-01 04:22:20 +00:00
|
|
|
|
pn = pd->pn_parent;
|
|
|
|
|
goto got_pnode;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
/* named node */
|
2001-10-19 01:43:06 +00:00
|
|
|
|
for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (pn->pn_type == pfstype_procdir)
|
|
|
|
|
pdn = pn;
|
2005-03-14 16:24:50 +00:00
|
|
|
|
else if (pn->pn_name[namelen] == '\0' &&
|
|
|
|
|
bcmp(pname, pn->pn_name, namelen) == 0)
|
2001-04-07 19:51:12 +00:00
|
|
|
|
goto got_pnode;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
|
|
|
|
|
/* process dependent node */
|
|
|
|
|
if ((pn = pdn) != NULL) {
|
|
|
|
|
pid = 0;
|
|
|
|
|
for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
|
|
|
|
|
if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
|
2001-04-07 19:51:12 +00:00
|
|
|
|
break;
|
|
|
|
|
if (i == cnp->cn_namelen)
|
|
|
|
|
goto got_pnode;
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (ENOENT);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
got_pnode:
|
2001-10-01 04:22:20 +00:00
|
|
|
|
if (pn != pd->pn_parent && !pn->pn_parent)
|
2001-04-07 19:51:12 +00:00
|
|
|
|
pn->pn_parent = pd;
|
2005-03-28 09:34:36 +00:00
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid)) {
|
|
|
|
|
error = ENOENT;
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
2002-07-08 01:50:14 +00:00
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (error)
|
2005-03-28 09:34:36 +00:00
|
|
|
|
goto failed;
|
2002-07-08 01:50:14 +00:00
|
|
|
|
|
2005-04-13 10:59:09 +00:00
|
|
|
|
if (cnp->cn_flags & ISDOTDOT)
|
|
|
|
|
vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (cnp->cn_flags & MAKEENTRY)
|
2001-06-10 18:39:21 +00:00
|
|
|
|
cache_enter(vn, *vpp, cnp);
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_RETURN (0);
|
2005-03-28 09:34:36 +00:00
|
|
|
|
failed:
|
|
|
|
|
if (cnp->cn_flags & ISDOTDOT)
|
|
|
|
|
vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
|
|
|
|
|
PFS_RETURN(error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Open a file or directory.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_open(struct vop_open_args *va)
|
|
|
|
|
{
|
2001-09-29 00:49:29 +00:00
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
2001-09-30 19:41:29 +00:00
|
|
|
|
int mode = va->a_mode;
|
2001-09-29 00:49:29 +00:00
|
|
|
|
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
|
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* check if the file is visible to the caller
|
|
|
|
|
*
|
|
|
|
|
* XXX Not sure if this is necessary, as the VFS system calls
|
2002-06-06 16:59:24 +00:00
|
|
|
|
* XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
|
|
|
|
|
* XXX calls pfs_visible(). There's a race condition here, but
|
2001-10-01 04:22:20 +00:00
|
|
|
|
* XXX calling pfs_visible() from here doesn't really close it,
|
|
|
|
|
* XXX and the only consequence of that race is an EIO further
|
|
|
|
|
* XXX down the line.
|
|
|
|
|
*/
|
|
|
|
|
if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (ENOENT);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-30 19:41:29 +00:00
|
|
|
|
/* check if the requested mode is permitted */
|
|
|
|
|
if (((mode & FREAD) && !(mode & PFS_RD)) ||
|
|
|
|
|
((mode & FWRITE) && !(mode & PFS_WR)))
|
|
|
|
|
PFS_RETURN (EPERM);
|
|
|
|
|
|
|
|
|
|
/* we don't support locking */
|
|
|
|
|
if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
|
|
|
|
|
PFS_RETURN (EOPNOTSUPP);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
PFS_RETURN (0);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read from a file
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_read(struct vop_read_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct uio *uio = va->a_uio;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct proc *proc = NULL;
|
2001-06-10 10:34:21 +00:00
|
|
|
|
struct sbuf *sb = NULL;
|
2003-10-02 15:00:55 +00:00
|
|
|
|
int error;
|
|
|
|
|
unsigned int buflen, offset, resid;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE((pn->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (vn->v_type != VREG)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EINVAL);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-30 19:41:29 +00:00
|
|
|
|
if (!(pn->pn_flags & PFS_RD))
|
|
|
|
|
PFS_RETURN (EBADF);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
|
2001-10-19 01:43:06 +00:00
|
|
|
|
if (pn->pn_func == NULL)
|
2001-10-26 18:52:47 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* This is necessary because either process' privileges may
|
|
|
|
|
* have changed since the open() call.
|
|
|
|
|
*/
|
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/* XXX duplicates bits of pfs_visible() */
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
_PHOLD(proc);
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
2001-09-25 13:25:30 +00:00
|
|
|
|
|
|
|
|
|
if (pn->pn_flags & PFS_RAWRD) {
|
2001-09-28 12:36:54 +00:00
|
|
|
|
error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2003-10-02 15:00:55 +00:00
|
|
|
|
/* Beaucoup sanity checks so we don't ask for bogus allocation. */
|
|
|
|
|
if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
|
|
|
|
|
(offset = uio->uio_offset) != uio->uio_offset ||
|
|
|
|
|
(resid = uio->uio_resid) != uio->uio_resid ||
|
|
|
|
|
(buflen = offset + resid) < offset || buflen > INT_MAX) {
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
|
|
|
|
PFS_RETURN (EINVAL);
|
|
|
|
|
}
|
2004-02-10 21:06:47 +00:00
|
|
|
|
if (buflen > MAXPHYS) {
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
|
|
|
|
PFS_RETURN (EIO);
|
|
|
|
|
}
|
2003-10-02 15:00:55 +00:00
|
|
|
|
sb = sbuf_new(sb, NULL, buflen, 0);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (sb == NULL) {
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
}
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-25 13:25:30 +00:00
|
|
|
|
error = (pn->pn_func)(curthread, proc, pn, sb, uio);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2001-06-10 21:39:01 +00:00
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
sbuf_delete(sb);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-06-10 21:39:01 +00:00
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-06-10 10:34:21 +00:00
|
|
|
|
sbuf_finish(sb);
|
2003-10-02 15:00:55 +00:00
|
|
|
|
error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
|
2001-06-10 10:34:21 +00:00
|
|
|
|
sbuf_delete(sb);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
/*
|
|
|
|
|
* Iterate through directory entries
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2001-10-19 01:43:06 +00:00
|
|
|
|
pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
|
2002-06-06 16:59:24 +00:00
|
|
|
|
struct pfs_node **pn, struct proc **p)
|
2001-06-10 18:39:21 +00:00
|
|
|
|
{
|
2003-08-18 19:23:01 +00:00
|
|
|
|
sx_assert(&allproc_lock, SX_LOCKED);
|
2001-10-01 04:22:20 +00:00
|
|
|
|
again:
|
2003-08-18 13:36:09 +00:00
|
|
|
|
if (*pn == NULL) {
|
|
|
|
|
/* first node */
|
|
|
|
|
*pn = pd->pn_nodes;
|
|
|
|
|
} else if ((*pn)->pn_type != pfstype_procdir) {
|
|
|
|
|
/* next node */
|
2001-10-19 01:43:06 +00:00
|
|
|
|
*pn = (*pn)->pn_next;
|
2003-08-18 13:36:09 +00:00
|
|
|
|
}
|
|
|
|
|
if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
|
|
|
|
|
/* next process */
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (*p == NULL)
|
|
|
|
|
*p = LIST_FIRST(&allproc);
|
|
|
|
|
else
|
|
|
|
|
*p = LIST_NEXT(*p, p_list);
|
2003-08-18 13:36:09 +00:00
|
|
|
|
/* out of processes: next node */
|
|
|
|
|
if (*p == NULL)
|
|
|
|
|
*pn = (*pn)->pn_next;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-19 01:43:06 +00:00
|
|
|
|
if ((*pn) == NULL)
|
2001-06-10 18:39:21 +00:00
|
|
|
|
return (-1);
|
2001-10-01 04:22:20 +00:00
|
|
|
|
|
|
|
|
|
if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
|
|
|
|
|
goto again;
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return directory entries.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_readdir(struct vop_readdir_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pd = pvd->pvd_pn;
|
2001-10-01 04:22:20 +00:00
|
|
|
|
pid_t pid = pvd->pvd_pid;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_node *pn;
|
2005-08-12 12:22:05 +00:00
|
|
|
|
struct dirent *entry;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct uio *uio;
|
|
|
|
|
struct proc *p;
|
|
|
|
|
off_t offset;
|
|
|
|
|
int error, i, resid;
|
2005-03-14 16:21:32 +00:00
|
|
|
|
char *buf, *ent;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE((pd->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (vn->v_type != VDIR)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (ENOTDIR);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
uio = va->a_uio;
|
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/* check if the directory is visible to the caller */
|
|
|
|
|
if (!pfs_visible(curthread, pd, pid))
|
|
|
|
|
PFS_RETURN (ENOENT);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* only allow reading entire entries */
|
|
|
|
|
offset = uio->uio_offset;
|
|
|
|
|
resid = uio->uio_resid;
|
2005-03-14 16:21:32 +00:00
|
|
|
|
if (offset < 0 || offset % PFS_DELEN != 0 ||
|
|
|
|
|
(resid && resid < PFS_DELEN))
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EINVAL);
|
2005-03-14 16:21:32 +00:00
|
|
|
|
if (resid == 0)
|
|
|
|
|
PFS_RETURN (0);
|
2004-07-09 11:43:37 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* skip unwanted entries */
|
2001-06-10 18:39:21 +00:00
|
|
|
|
sx_slock(&allproc_lock);
|
2001-10-19 01:43:06 +00:00
|
|
|
|
for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
|
|
|
|
|
if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
|
|
|
|
|
/* nothing left... */
|
|
|
|
|
sx_sunlock(&allproc_lock);
|
|
|
|
|
PFS_RETURN (0);
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* fill in entries */
|
2005-08-12 12:22:05 +00:00
|
|
|
|
ent = buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
|
2005-03-14 16:21:32 +00:00
|
|
|
|
while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 &&
|
|
|
|
|
resid >= PFS_DELEN) {
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry = (struct dirent *)ent;
|
|
|
|
|
entry->d_reclen = PFS_DELEN;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (!pn->pn_parent)
|
|
|
|
|
pn->pn_parent = pd;
|
|
|
|
|
if (!pn->pn_fileno)
|
|
|
|
|
pfs_fileno_alloc(pi, pn);
|
2001-10-01 04:22:20 +00:00
|
|
|
|
if (pid != NO_PID)
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_fileno = pn->pn_fileno * NO_PID + pid;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
else
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_fileno = pn->pn_fileno;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* PFS_DELEN was picked to fit PFS_NAMLEN */
|
|
|
|
|
for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_name[i] = pn->pn_name[i];
|
|
|
|
|
entry->d_name[i] = 0;
|
|
|
|
|
entry->d_namlen = i;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
switch (pn->pn_type) {
|
2001-06-10 18:39:21 +00:00
|
|
|
|
case pfstype_procdir:
|
|
|
|
|
KASSERT(p != NULL,
|
|
|
|
|
("reached procdir node with p == NULL"));
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
|
|
|
|
|
entry->d_namlen = snprintf(entry->d_name,
|
2001-06-10 18:39:21 +00:00
|
|
|
|
PFS_NAMELEN, "%d", p->p_pid);
|
|
|
|
|
/* fall through */
|
2001-04-07 19:51:12 +00:00
|
|
|
|
case pfstype_root:
|
|
|
|
|
case pfstype_dir:
|
|
|
|
|
case pfstype_this:
|
|
|
|
|
case pfstype_parent:
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_type = DT_DIR;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
break;
|
|
|
|
|
case pfstype_file:
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_type = DT_REG;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
break;
|
|
|
|
|
case pfstype_symlink:
|
2005-08-12 12:22:05 +00:00
|
|
|
|
entry->d_type = DT_LNK;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
|
|
|
|
|
}
|
2005-08-12 12:22:05 +00:00
|
|
|
|
PFS_TRACE((entry->d_name));
|
2001-04-07 19:51:12 +00:00
|
|
|
|
offset += PFS_DELEN;
|
|
|
|
|
resid -= PFS_DELEN;
|
2005-03-14 16:21:32 +00:00
|
|
|
|
ent += PFS_DELEN;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
2001-06-10 18:39:21 +00:00
|
|
|
|
sx_sunlock(&allproc_lock);
|
2005-03-14 16:21:32 +00:00
|
|
|
|
error = uiomove(buf, ent - buf, uio);
|
|
|
|
|
free(buf, M_IOV);
|
2004-07-09 11:43:37 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read a symbolic link
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_readlink(struct vop_readlink_args *va)
|
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct uio *uio = va->a_uio;
|
2001-06-10 18:39:21 +00:00
|
|
|
|
struct proc *proc = NULL;
|
2003-10-02 15:00:55 +00:00
|
|
|
|
char buf[MAXPATHLEN];
|
2001-04-07 19:51:12 +00:00
|
|
|
|
struct sbuf sb;
|
2003-10-02 15:00:55 +00:00
|
|
|
|
int error;
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE((pn->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
if (vn->v_type != VLNK)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EINVAL);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
|
2001-10-19 01:43:06 +00:00
|
|
|
|
if (pn->pn_func == NULL)
|
2001-10-26 18:52:47 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-06-10 18:39:21 +00:00
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
_PHOLD(proc);
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/* sbuf_new() can't fail with a static buffer */
|
|
|
|
|
sbuf_new(&sb, buf, sizeof buf, 0);
|
|
|
|
|
|
2001-09-25 13:25:30 +00:00
|
|
|
|
error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
|
2001-06-10 18:39:21 +00:00
|
|
|
|
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-06-10 21:39:01 +00:00
|
|
|
|
if (error) {
|
|
|
|
|
sbuf_delete(&sb);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-06-10 21:39:01 +00:00
|
|
|
|
}
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
sbuf_finish(&sb);
|
2003-10-02 15:00:55 +00:00
|
|
|
|
error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
sbuf_delete(&sb);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reclaim a vnode
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_reclaim(struct vop_reclaim_args *va)
|
|
|
|
|
{
|
2001-10-19 01:43:06 +00:00
|
|
|
|
PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
|
2001-12-19 23:58:09 +00:00
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
return (pfs_vncache_free(va->a_vp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set attributes
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
pfs_setattr(struct vop_setattr_args *va)
|
|
|
|
|
{
|
2001-10-19 01:43:06 +00:00
|
|
|
|
PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
|
2002-02-04 18:21:59 +00:00
|
|
|
|
|
|
|
|
|
PFS_RETURN (EOPNOTSUPP);
|
2001-04-07 19:51:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2005-04-30 16:27:20 +00:00
|
|
|
|
* Write to a file
|
2001-04-07 19:51:12 +00:00
|
|
|
|
*/
|
2001-09-25 13:25:30 +00:00
|
|
|
|
static int
|
2004-12-01 23:16:38 +00:00
|
|
|
|
pfs_write(struct vop_write_args *va)
|
2001-09-25 13:25:30 +00:00
|
|
|
|
{
|
|
|
|
|
struct vnode *vn = va->a_vp;
|
|
|
|
|
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
|
|
|
|
|
struct pfs_node *pn = pvd->pvd_pn;
|
|
|
|
|
struct uio *uio = va->a_uio;
|
|
|
|
|
struct proc *proc = NULL;
|
2001-09-29 00:49:29 +00:00
|
|
|
|
struct sbuf sb;
|
2001-09-25 13:25:30 +00:00
|
|
|
|
int error;
|
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
PFS_TRACE((pn->pn_name));
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-25 13:25:30 +00:00
|
|
|
|
if (vn->v_type != VREG)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EINVAL);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
|
2001-09-30 19:41:29 +00:00
|
|
|
|
if (!(pn->pn_flags & PFS_WR))
|
|
|
|
|
PFS_RETURN (EBADF);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
|
2001-10-19 01:43:06 +00:00
|
|
|
|
if (pn->pn_func == NULL)
|
2001-10-26 18:52:47 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-10-01 04:22:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* This is necessary because either process' privileges may
|
|
|
|
|
* have changed since the open() call.
|
|
|
|
|
*/
|
|
|
|
|
if (!pfs_visible(curthread, pn, pvd->pvd_pid))
|
|
|
|
|
PFS_RETURN (EIO);
|
|
|
|
|
|
|
|
|
|
/* XXX duplicates bits of pfs_visible() */
|
2001-09-25 13:25:30 +00:00
|
|
|
|
if (pvd->pvd_pid != NO_PID) {
|
|
|
|
|
if ((proc = pfind(pvd->pvd_pid)) == NULL)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (EIO);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
_PHOLD(proc);
|
|
|
|
|
PROC_UNLOCK(proc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pn->pn_flags & PFS_RAWWR) {
|
2001-09-28 12:36:54 +00:00
|
|
|
|
error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
}
|
2001-09-29 00:49:29 +00:00
|
|
|
|
|
|
|
|
|
sbuf_uionew(&sb, uio, &error);
|
|
|
|
|
if (error)
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
|
|
|
|
|
|
|
|
|
|
if (proc != NULL)
|
|
|
|
|
PRELE(proc);
|
2002-06-06 16:59:24 +00:00
|
|
|
|
|
2001-09-29 00:49:29 +00:00
|
|
|
|
sbuf_delete(&sb);
|
2001-09-30 19:41:29 +00:00
|
|
|
|
PFS_RETURN (error);
|
2001-09-25 13:25:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-07 19:51:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Vnode operations
|
|
|
|
|
*/
|
2004-12-01 23:16:38 +00:00
|
|
|
|
struct vop_vector pfs_vnodeops = {
|
|
|
|
|
.vop_default = &default_vnodeops,
|
2005-01-13 18:59:48 +00:00
|
|
|
|
|
2004-12-01 23:16:38 +00:00
|
|
|
|
.vop_access = pfs_access,
|
2005-03-14 16:24:50 +00:00
|
|
|
|
.vop_cachedlookup = pfs_lookup,
|
2004-12-01 23:16:38 +00:00
|
|
|
|
.vop_close = pfs_close,
|
|
|
|
|
.vop_create = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_getattr = pfs_getattr,
|
|
|
|
|
.vop_getextattr = pfs_getextattr,
|
|
|
|
|
.vop_ioctl = pfs_ioctl,
|
|
|
|
|
.vop_link = VOP_EOPNOTSUPP,
|
2005-03-14 16:24:50 +00:00
|
|
|
|
.vop_lookup = vfs_cache_lookup,
|
2004-12-01 23:16:38 +00:00
|
|
|
|
.vop_mkdir = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_mknod = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_open = pfs_open,
|
|
|
|
|
.vop_read = pfs_read,
|
|
|
|
|
.vop_readdir = pfs_readdir,
|
|
|
|
|
.vop_readlink = pfs_readlink,
|
|
|
|
|
.vop_reclaim = pfs_reclaim,
|
|
|
|
|
.vop_remove = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_rename = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_rmdir = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_setattr = pfs_setattr,
|
|
|
|
|
.vop_symlink = VOP_EOPNOTSUPP,
|
|
|
|
|
.vop_write = pfs_write,
|
|
|
|
|
/* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
|
2001-04-07 19:51:12 +00:00
|
|
|
|
};
|