pseudofs_vnops.c revision 77964
186764Sjlemon/*-
2141063Srwatson * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
386764Sjlemon * All rights reserved.
486764Sjlemon *
586764Sjlemon * Redistribution and use in source and binary forms, with or without
6141063Srwatson * modification, are permitted provided that the following conditions
7141063Srwatson * are met:
886764Sjlemon * 1. Redistributions of source code must retain the above copyright
986764Sjlemon *    notice, this list of conditions and the following disclaimer
1086764Sjlemon *    in this position and unchanged.
1186764Sjlemon * 2. Redistributions in binary form must reproduce the above copyright
1286764Sjlemon *    notice, this list of conditions and the following disclaimer in the
1386764Sjlemon *    documentation and/or other materials provided with the distribution.
1486764Sjlemon * 3. The name of the author may not be used to endorse or promote products
1586764Sjlemon *    derived from this software without specific prior written permission.
1686764Sjlemon *
1786764Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1886764Sjlemon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1986764Sjlemon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2086764Sjlemon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2186764Sjlemon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2286764Sjlemon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2386764Sjlemon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2486764Sjlemon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2586764Sjlemon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2686764Sjlemon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2786764Sjlemon *
2886764Sjlemon *	$FreeBSD: head/sys/fs/pseudofs/pseudofs_vnops.c 77964 2001-06-10 10:34:21Z des $
2986764Sjlemon */
3086764Sjlemon
3186764Sjlemon#include <sys/param.h>
3286764Sjlemon#include <sys/kernel.h>
3386764Sjlemon#include <sys/systm.h>
34125680Sbms#include <sys/ctype.h>
3586764Sjlemon#include <sys/dirent.h>
3686764Sjlemon#include <sys/mount.h>
37101106Srwatson#include <sys/namei.h>
38118864Sharti#include <sys/proc.h>
39130989Sps#include <sys/sbuf.h>
4086764Sjlemon#include <sys/sx.h>
4186764Sjlemon#include <sys/sysctl.h>
4286764Sjlemon#include <sys/vnode.h>
4386764Sjlemon
4486764Sjlemon#include <fs/pseudofs/pseudofs.h>
4586764Sjlemon#include <fs/pseudofs/pseudofs_internal.h>
46101106Srwatson
4786764Sjlemon/*
4886764Sjlemon * Verify permissions
4986764Sjlemon */
5086764Sjlemonstatic int
5186764Sjlemonpfs_access(struct vop_access_args *va)
5286764Sjlemon{
5386764Sjlemon	struct vnode *vn = va->a_vp;
5486764Sjlemon	struct vattr vattr;
5586764Sjlemon	int error;
5686764Sjlemon
5786764Sjlemon	error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_p);
5886764Sjlemon	if (error)
5986764Sjlemon		return (error);
6086764Sjlemon	error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
6186764Sjlemon	    vattr.va_gid, va->a_mode, va->a_cred, NULL);
6286764Sjlemon	return (error);
63152592Sandre}
6486764Sjlemon
6586764Sjlemon/*
6686764Sjlemon * Close a file or directory
6786764Sjlemon */
6886764Sjlemonstatic int
6986764Sjlemonpfs_close(struct vop_close_args *va)
7086764Sjlemon{
7186764Sjlemon	return (0);
72118864Sharti}
73118864Sharti
74118864Sharti/*
7586764Sjlemon * Get file attributes
7686764Sjlemon */
7786764Sjlemonstatic int
7886764Sjlemonpfs_getattr(struct vop_getattr_args *va)
79118864Sharti{
80118864Sharti	struct vnode *vn = va->a_vp;
81118864Sharti	struct pfs_node *pn = (struct pfs_node *)vn->v_data;
8286764Sjlemon	struct vattr *vap = va->a_vap;
8386764Sjlemon
8486764Sjlemon	VATTR_NULL(vap);
8586764Sjlemon	vap->va_type = vn->v_type;
8686764Sjlemon	vap->va_mode = pn->pn_mode;
8786764Sjlemon	vap->va_fileid = pn->pn_fileno;
8886764Sjlemon	vap->va_flags = 0;
8986764Sjlemon	vap->va_blocksize = PAGE_SIZE;
9086764Sjlemon	vap->va_bytes = vap->va_size = 0;
9186764Sjlemon	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
9286764Sjlemon	vap->va_nlink = 1;
93105199Ssam	nanotime(&vap->va_ctime);
94105199Ssam	vap->va_atime = vap->va_mtime = vap->va_ctime;
95105199Ssam	vap->va_uid = pn->pn_uid;
96105199Ssam	vap->va_gid = pn->pn_gid;
97105199Ssam
98105199Ssam	return (0);
99105199Ssam}
100105199Ssam
10186764Sjlemon/*
10292760Sjeff * Look up a file or directory
10386764Sjlemon */
10488180Sjlemonstatic int
10588180Sjlemonpfs_lookup(struct vop_lookup_args *va)
106133874Srwatson{
10788180Sjlemon	struct vnode *dvp = va->a_dvp;
10888180Sjlemon	struct vnode **vpp = va->a_vpp;
10986764Sjlemon	struct componentname *cnp = va->a_cnp;
11086764Sjlemon#if 0
11188180Sjlemon	struct pfs_info *pi = (struct pfs_info *)dvp->v_mount->mnt_data;
11286764Sjlemon#endif
113118864Sharti	struct pfs_node *pd = (struct pfs_node *)dvp->v_data, *pn;
114118864Sharti	struct proc *p;
115118864Sharti	char *pname;
11686764Sjlemon	int error, i;
117118864Sharti	pid_t pid;
118133874Srwatson
11996602Srwatson	if (dvp->v_type != VDIR)
12086764Sjlemon		return (ENOTDIR);
121132307Sdwmalone
12288180Sjlemon	/* don't support CREATE, RENAME or DELETE */
12388180Sjlemon	if (cnp->cn_nameiop != LOOKUP)
12486764Sjlemon		return (EROFS);
12586764Sjlemon
12686764Sjlemon	/* shortcut */
12786764Sjlemon	if (cnp->cn_namelen >= PFS_NAMELEN)
12886764Sjlemon		return (ENOENT);
12986764Sjlemon
13086764Sjlemon	/* self */
13186764Sjlemon	pname = cnp->cn_nameptr;
13286764Sjlemon	if (cnp->cn_namelen == 1 && *pname == '.') {
13386764Sjlemon		pn = pd;
13486764Sjlemon		*vpp = dvp;
13586764Sjlemon		VREF(dvp);
13686764Sjlemon		goto got_vnode;
13786764Sjlemon	}
13892760Sjeff
13986764Sjlemon	/* parent */
14086764Sjlemon	if (cnp->cn_flags & ISDOTDOT) {
14186764Sjlemon		if (pd->pn_type == pfstype_root)
14286764Sjlemon			return (EIO);
14386764Sjlemon		KASSERT(pd->pn_parent, ("non-root directory has no parent"));
14486764Sjlemon		return pfs_vncache_alloc(dvp->v_mount, vpp, pd->pn_parent);
14586764Sjlemon	}
14686764Sjlemon
14786764Sjlemon	/* process dependent */
14886764Sjlemon	for (i = 0, pid = 0; i < cnp->cn_namelen && isdigit(pname[i]); ++i)
14986764Sjlemon		pid = pid * 10 + pname[i] - '0';
15086764Sjlemon	/* XXX assume that 8 digits is the maximum safe length for a pid */
15186764Sjlemon	if (i == cnp->cn_namelen && i < 8) {
15286764Sjlemon		/* see if this directory has process-dependent children */
153121307Ssilby		for (pn = pd->pn_nodes; pn->pn_type; ++pn)
15486764Sjlemon			if (pn->pn_type == pfstype_procdep)
15586764Sjlemon				break;
156121307Ssilby		if (pn->pn_type) {
15786764Sjlemon			/* XXX pfind(0) should DTRT here */
15886764Sjlemon			p = pid ? pfind(pid) : &proc0;
15986764Sjlemon			if (p == NULL)
16086764Sjlemon				return (ENOENT);
16186764Sjlemon			if (p_can(cnp->cn_proc, p, P_CAN_SEE, NULL))
162121307Ssilby				/* pretend it doesn't exist */
16386764Sjlemon				return (ENOENT);
16486764Sjlemon#if 0
16586764Sjlemon			if (!pn->pn_shadow)
16686764Sjlemon				pfs_create_shadow(pn, p);
16786764Sjlemon			pn = pn->pn_shadow;
16886764Sjlemon			goto got_pnode;
16986764Sjlemon#else
170133874Srwatson			/* not yet implemented */
17186764Sjlemon			return (EIO);
17286764Sjlemon#endif
173133874Srwatson		}
17486764Sjlemon	}
17586764Sjlemon
176133874Srwatson	/* something else */
17786764Sjlemon	for (pn = pd->pn_nodes; pn->pn_type; ++pn) {
178133874Srwatson		for (i = 0; i < cnp->cn_namelen && pn->pn_name[i]; ++i)
179133874Srwatson			if (pname[i] != pn->pn_name[i])
18086764Sjlemon				break;
18186764Sjlemon		if (i == cnp->cn_namelen)
18286764Sjlemon			goto got_pnode;
18389667Sjlemon	}
18486764Sjlemon
18586764Sjlemon	return (ENOENT);
18686764Sjlemon got_pnode:
18786764Sjlemon	if (!pn->pn_parent)
18886764Sjlemon		pn->pn_parent = pd;
18986764Sjlemon	error = pfs_vncache_alloc(dvp->v_mount, vpp, pn);
19086764Sjlemon	if (error)
191106696Salfred		return error;
192106696Salfred got_vnode:
193106696Salfred	if (cnp->cn_flags & MAKEENTRY)
194106696Salfred		cache_enter(dvp, *vpp, cnp);
195106696Salfred	return (0);
196106696Salfred}
197106696Salfred
198106696Salfred/*
19986764Sjlemon * Open a file or directory.
20086764Sjlemon */
20186764Sjlemonstatic int
20286764Sjlemonpfs_open(struct vop_open_args *va)
20386764Sjlemon{
20486764Sjlemon	/* XXX */
20586764Sjlemon	return (0);
206122922Sandre}
20792760Sjeff
20886764Sjlemon/*
20986764Sjlemon * Read from a file
21086764Sjlemon */
21186764Sjlemonstatic int
21286764Sjlemonpfs_read(struct vop_read_args *va)
21386764Sjlemon{
21486764Sjlemon	struct vnode *vn = va->a_vp;
21586764Sjlemon	struct pfs_node *pn = vn->v_data;
21686764Sjlemon	struct uio *uio = va->a_uio;
21786764Sjlemon	struct sbuf *sb = NULL;
21886764Sjlemon	char *ps;
21986764Sjlemon	int error, xlen;
22086764Sjlemon
22186764Sjlemon	if (vn->v_type != VREG)
22286764Sjlemon		return (EINVAL);
223133874Srwatson
22486764Sjlemon	sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
225133874Srwatson	if (sb == NULL)
22686764Sjlemon		return (EIO);
227133874Srwatson
22886764Sjlemon	error = (pn->pn_func)(pn, curproc, sb);
229149455Sglebius
230133874Srwatson	/* XXX we should possibly detect and handle overflows */
231149455Sglebius	sbuf_finish(sb);
232133874Srwatson	ps = sbuf_data(sb) + uio->uio_offset;
23386764Sjlemon	xlen = sbuf_len(sb) - uio->uio_offset;
23486764Sjlemon	xlen = imin(xlen, uio->uio_resid);
23586764Sjlemon	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
23686764Sjlemon	sbuf_delete(sb);
23786764Sjlemon	return (error);
238111119Simp}
23986764Sjlemon
24086764Sjlemon/*
24186764Sjlemon * Return directory entries.
24286764Sjlemon */
24386764Sjlemonstatic int
24486764Sjlemonpfs_readdir(struct vop_readdir_args *va)
24586764Sjlemon{
24686764Sjlemon	struct vnode *vn = va->a_vp;
24786814Sbde	struct pfs_info *pi;
24886764Sjlemon	struct pfs_node *pd, *pn;
249142906Sglebius	struct dirent entry;
25086764Sjlemon	struct uio *uio;
25186764Sjlemon#if 0
25286764Sjlemon	struct proc *p;
25386764Sjlemon#endif
25486764Sjlemon	off_t offset;
25586764Sjlemon	int error, i, resid;
25686764Sjlemon
25792760Sjeff	if (vn->v_type != VDIR)
258133517Sandre		return (ENOTDIR);
25992760Sjeff	pi = (struct pfs_info *)vn->v_mount->mnt_data;
260124848Sandre	pd = (struct pfs_node *)vn->v_data;
26186764Sjlemon	pn = pd->pn_nodes;
26286764Sjlemon	uio = va->a_uio;
26388180Sjlemon
26486764Sjlemon	/* only allow reading entire entries */
26586764Sjlemon	offset = uio->uio_offset;
26686764Sjlemon	resid = uio->uio_resid;
26786764Sjlemon	if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
26886764Sjlemon		return (EINVAL);
269122496Ssam
27086764Sjlemon	/* skip unwanted entries */
271122496Ssam	for (; pn->pn_type && offset > 0; ++pn, offset -= PFS_DELEN)
272122496Ssam		/* nothing */ ;
27386764Sjlemon
27486764Sjlemon	/* fill in entries */
27586764Sjlemon	entry.d_reclen = PFS_DELEN;
27686764Sjlemon	for (; pn->pn_type && resid > 0; ++pn) {
27786764Sjlemon		if (!pn->pn_parent)
27886764Sjlemon			pn->pn_parent = pd;
27986764Sjlemon		if (!pn->pn_fileno)
28086764Sjlemon			pfs_fileno_alloc(pi, pn);
28186764Sjlemon		entry.d_fileno = pn->pn_fileno;
28288180Sjlemon		/* PFS_DELEN was picked to fit PFS_NAMLEN */
28386764Sjlemon		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
28486764Sjlemon			entry.d_name[i] = pn->pn_name[i];
28586764Sjlemon		entry.d_name[i] = 0;
28686764Sjlemon		entry.d_namlen = i;
28786764Sjlemon		switch (pn->pn_type) {
28886764Sjlemon		case pfstype_root:
28986764Sjlemon		case pfstype_dir:
29086764Sjlemon		case pfstype_this:
29186764Sjlemon		case pfstype_parent:
29286764Sjlemon			entry.d_type = DT_DIR;
29386764Sjlemon			break;
29486764Sjlemon		case pfstype_file:
29586764Sjlemon			entry.d_type = DT_REG;
29686764Sjlemon			break;
29788180Sjlemon		case pfstype_symlink:
29886764Sjlemon			entry.d_type = DT_LNK;
29986764Sjlemon			break;
30086764Sjlemon		case pfstype_procdep:
30186764Sjlemon			/* don't handle process-dependent nodes here */
30286764Sjlemon			continue;
30386764Sjlemon		default:
30486764Sjlemon			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
30586764Sjlemon		}
30686764Sjlemon		if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio)))
30786764Sjlemon			return (error);
30886764Sjlemon		offset += PFS_DELEN;
30986764Sjlemon		resid -= PFS_DELEN;
31086764Sjlemon	}
31186764Sjlemon#if 0
31286764Sjlemon	for (pn = pd->pn_nodes; pn->pn_type && resid > 0; ++pn) {
31386764Sjlemon		if (pn->pn_type != pfstype_procdep)
31486764Sjlemon			continue;
31586764Sjlemon
31686764Sjlemon		sx_slock(&allproc_lock);
317122496Ssam		p = LIST_FIRST(&allproc);
31886764Sjlemon
31986764Sjlemon		sx_sunlock(&allproc_lock);
32086764Sjlemon		offset += PFS_DELEN;
32186764Sjlemon		resid -= PFS_DELEN;
32286764Sjlemon		break;
32386764Sjlemon	}
32486764Sjlemon#endif
32586764Sjlemon
32686764Sjlemon	uio->uio_offset += offset;
32786764Sjlemon	return (0);
32886764Sjlemon}
32986764Sjlemon
33086764Sjlemon/*
33186764Sjlemon * Read a symbolic link
33286764Sjlemon */
33386764Sjlemonstatic int
33486764Sjlemonpfs_readlink(struct vop_readlink_args *va)
33586764Sjlemon{
33686764Sjlemon	struct vnode *vn = va->a_vp;
33786764Sjlemon	struct pfs_node *pn = vn->v_data;
33886764Sjlemon	struct uio *uio = va->a_uio;
33986764Sjlemon	char buf[MAXPATHLEN], *ps;
34086764Sjlemon	struct sbuf sb;
34186764Sjlemon	int error, xlen;
34286764Sjlemon
34386764Sjlemon	if (vn->v_type != VLNK)
34486764Sjlemon		return (EINVAL);
34586764Sjlemon
34686764Sjlemon	/* sbuf_new() can't fail with a static buffer */
34786764Sjlemon	sbuf_new(&sb, buf, sizeof buf, 0);
34886764Sjlemon
34986764Sjlemon	error = (pn->pn_func)(pn, curproc, &sb);
35086764Sjlemon
35188195Sjlemon	/* XXX we should detect and handle overflows */
35286764Sjlemon	sbuf_finish(&sb);
35386764Sjlemon	ps = sbuf_data(&sb) + uio->uio_offset;
35486764Sjlemon	xlen = sbuf_len(&sb) - uio->uio_offset;
355110737Shsu	xlen = imin(xlen, uio->uio_resid);
356133874Srwatson	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
357133874Srwatson	sbuf_delete(&sb);
358122496Ssam	return (error);
359122501Ssam}
360133874Srwatson
361133874Srwatson/*
362133874Srwatson * Reclaim a vnode
36386764Sjlemon */
364133874Srwatsonstatic int
36586764Sjlemonpfs_reclaim(struct vop_reclaim_args *va)
36686764Sjlemon{
36786764Sjlemon	return (pfs_vncache_free(va->a_vp));
36886764Sjlemon}
36986764Sjlemon
37086764Sjlemon/*
37186764Sjlemon * Set attributes
372108703Shsu */
37398982Sjlemonstatic int
37486764Sjlemonpfs_setattr(struct vop_setattr_args *va)
37586764Sjlemon{
37686764Sjlemon	if (va->a_vap->va_flags != VNOVAL)
37786764Sjlemon		return (EOPNOTSUPP);
37898982Sjlemon	return (0);
37998982Sjlemon}
38098982Sjlemon
38198982Sjlemon/*
38298982Sjlemon * Dummy operations
383118864Sharti */
384118864Shartistatic int pfs_erofs(void *va)		{ return (EROFS); }
385118864Shartistatic int pfs_null(void *va)		{ return (0); }
38686764Sjlemon
387118864Sharti/*
38898982Sjlemon * Vnode operations
38986764Sjlemon */
39086764Sjlemonvop_t **pfs_vnodeop_p;
39186764Sjlemonstatic struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
39286764Sjlemon	{ &vop_default_desc,		(vop_t *)vop_defaultop	},
39386764Sjlemon	{ &vop_access_desc,		(vop_t *)pfs_access	},
39486764Sjlemon	{ &vop_close_desc,		(vop_t *)pfs_close	},
39586764Sjlemon	{ &vop_create_desc,		(vop_t *)pfs_erofs	},
396122501Ssam	{ &vop_getattr_desc,		(vop_t *)pfs_getattr	},
39786764Sjlemon	{ &vop_link_desc,		(vop_t *)pfs_erofs	},
39886764Sjlemon	{ &vop_lookup_desc,		(vop_t *)pfs_lookup	},
39986764Sjlemon	{ &vop_mkdir_desc,		(vop_t *)pfs_erofs	},
40086764Sjlemon	{ &vop_open_desc,		(vop_t *)pfs_open	},
40186764Sjlemon	{ &vop_read_desc,		(vop_t *)pfs_read	},
40286764Sjlemon	{ &vop_readdir_desc,		(vop_t *)pfs_readdir	},
40386764Sjlemon	{ &vop_readlink_desc,		(vop_t *)pfs_readlink	},
40486764Sjlemon	{ &vop_reclaim_desc,		(vop_t *)pfs_reclaim	},
40586764Sjlemon	{ &vop_remove_desc,		(vop_t *)pfs_erofs	},
40686764Sjlemon	{ &vop_rename_desc,		(vop_t *)pfs_erofs	},
40786764Sjlemon	{ &vop_rmdir_desc,		(vop_t *)pfs_erofs	},
40886764Sjlemon	{ &vop_setattr_desc,		(vop_t *)pfs_setattr	},
40986764Sjlemon	{ &vop_symlink_desc,		(vop_t *)pfs_erofs	},
410122496Ssam	{ &vop_write_desc,		(vop_t *)pfs_erofs	},
411122496Ssam	/* XXX I've probably forgotten a few that need pfs_erofs */
41286764Sjlemon	{ NULL,				(vop_t *)NULL		}
41386764Sjlemon};
41486764Sjlemon
41586764Sjlemonstatic struct vnodeopv_desc pfs_vnodeop_opv_desc =
41686764Sjlemon	{ &pfs_vnodeop_p, pfs_vnodeop_entries };
41786764Sjlemon
418122496SsamVNODEOP_SET(pfs_vnodeop_opv_desc);
41986764Sjlemon
42086764Sjlemon