xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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$
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/lock.h>
37 #include <sys/mount.h>
38 #include <sys/mutex.h>
39 #include <sys/namei.h>
40 #include <sys/proc.h>
41 #include <sys/sbuf.h>
42 #include <sys/sx.h>
43 #include <sys/sysctl.h>
44 #include <sys/vnode.h>
45 
46 #include <fs/pseudofs/pseudofs.h>
47 #include <fs/pseudofs/pseudofs_internal.h>
48 
49 /*
50  * Verify permissions
51  */
52 static int
53 pfs_access(struct vop_access_args *va)
54 {
55 	struct vnode *vn = va->a_vp;
56 	struct vattr vattr;
57 	int error;
58 
59 	error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_p);
60 	if (error)
61 		return (error);
62 	error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
63 	    vattr.va_gid, va->a_mode, va->a_cred, NULL);
64 	return (error);
65 }
66 
67 /*
68  * Close a file or directory
69  */
70 static int
71 pfs_close(struct vop_close_args *va)
72 {
73 	return (0);
74 }
75 
76 /*
77  * Get file attributes
78  */
79 static int
80 pfs_getattr(struct vop_getattr_args *va)
81 {
82 	struct vnode *vn = va->a_vp;
83 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
84 	struct pfs_node *pn = pvd->pvd_pn;
85 	struct vattr *vap = va->a_vap;
86 
87 	VATTR_NULL(vap);
88 	vap->va_type = vn->v_type;
89 	vap->va_mode = pn->pn_mode;
90 	vap->va_fileid = pn->pn_fileno;
91 	vap->va_flags = 0;
92 	vap->va_blocksize = PAGE_SIZE;
93 	vap->va_bytes = vap->va_size = 0;
94 	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
95 	vap->va_nlink = 1;
96 	nanotime(&vap->va_ctime);
97 	vap->va_atime = vap->va_mtime = vap->va_ctime;
98 	vap->va_uid = pn->pn_uid;
99 	vap->va_gid = pn->pn_gid;
100 
101 	return (0);
102 }
103 
104 /*
105  * Look up a file or directory
106  */
107 static int
108 pfs_lookup(struct vop_lookup_args *va)
109 {
110 	struct vnode *vn = va->a_dvp;
111 	struct vnode **vpp = va->a_vpp;
112 	struct componentname *cnp = va->a_cnp;
113 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
114 	struct pfs_node *pd = pvd->pvd_pn;
115 	struct pfs_node *pn, *pdn = NULL;
116 	pid_t pid = pvd->pvd_pid;
117 	char *pname;
118 	int error, i, namelen;
119 
120 	if (vn->v_type != VDIR)
121 		return (ENOTDIR);
122 
123 	/* don't support CREATE, RENAME or DELETE */
124 	if (cnp->cn_nameiop != LOOKUP)
125 		return (EROFS);
126 
127 	/* shortcut */
128 	if (cnp->cn_namelen >= PFS_NAMELEN)
129 		return (ENOENT);
130 
131 	/* self */
132 	namelen = cnp->cn_namelen;
133 	pname = cnp->cn_nameptr;
134 	if (namelen == 1 && *pname == '.') {
135 		pn = pd;
136 		*vpp = vn;
137 		VREF(vn);
138 		goto got_vnode;
139 	}
140 
141 	/* parent */
142 	if (cnp->cn_flags & ISDOTDOT) {
143 		if (pd->pn_type == pfstype_root)
144 			return (EIO);
145 		KASSERT(pd->pn_parent, ("non-root directory has no parent"));
146 		/*
147 		 * This one is tricky.  Descendents of procdir nodes
148 		 * inherit their parent's process affinity, but
149 		 * there's no easy reverse mapping.  For simplicity,
150 		 * we assume that if this node is a procdir, its
151 		 * parent isn't (which is correct as long as
152 		 * descendents of procdir nodes are never procdir
153 		 * nodes themselves)
154 		 */
155 		if (pd->pn_type == pfstype_procdir)
156 			pid = NO_PID;
157 		return pfs_vncache_alloc(vn->v_mount, vpp, pd->pn_parent, pid);
158 	}
159 
160 	/* named node */
161 	for (pn = pd->pn_nodes; pn->pn_type; ++pn)
162 		if (pn->pn_type == pfstype_procdir)
163 			pdn = pn;
164 		else if (pn->pn_name[namelen] == '\0'
165 		    && bcmp(pname, pn->pn_name, namelen) == 0)
166 			goto got_pnode;
167 
168 	/* process dependent node */
169 	if ((pn = pdn) != NULL) {
170 		pid = 0;
171 		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
172 			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
173 				break;
174 		if (i == cnp->cn_namelen)
175 			goto got_pnode;
176 	}
177 
178 	return (ENOENT);
179  got_pnode:
180 	if (!pn->pn_parent)
181 		pn->pn_parent = pd;
182 	error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
183 	if (error)
184 		return error;
185  got_vnode:
186 	if (cnp->cn_flags & MAKEENTRY)
187 		cache_enter(vn, *vpp, cnp);
188 	return (0);
189 }
190 
191 /*
192  * Open a file or directory.
193  */
194 static int
195 pfs_open(struct vop_open_args *va)
196 {
197 	/* XXX */
198 	return (0);
199 }
200 
201 /*
202  * Read from a file
203  */
204 static int
205 pfs_read(struct vop_read_args *va)
206 {
207 	struct vnode *vn = va->a_vp;
208 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
209 	struct pfs_node *pn = pvd->pvd_pn;
210 	struct uio *uio = va->a_uio;
211 	struct proc *proc = NULL;
212 	struct sbuf *sb = NULL;
213 	char *ps;
214 	int error, xlen;
215 
216 	if (vn->v_type != VREG)
217 		return (EINVAL);
218 
219 	if (pvd->pvd_pid != NO_PID) {
220 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
221 			return (EIO);
222 		_PHOLD(proc);
223 		PROC_UNLOCK(proc);
224 	}
225 
226 	sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
227 	if (sb == NULL) {
228 		if (proc != NULL)
229 			PRELE(proc);
230 		return (EIO);
231 	}
232 
233 	error = (pn->pn_func)(curproc, proc, pn, sb);
234 
235 	if (proc != NULL)
236 		PRELE(proc);
237 
238 	if (error) {
239 		sbuf_delete(sb);
240 		return (error);
241 	}
242 
243 	/* XXX we should possibly detect and handle overflows */
244 	sbuf_finish(sb);
245 	ps = sbuf_data(sb) + uio->uio_offset;
246 	xlen = sbuf_len(sb) - uio->uio_offset;
247 	xlen = imin(xlen, uio->uio_resid);
248 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
249 	sbuf_delete(sb);
250 	return (error);
251 }
252 
253 /*
254  * Iterate through directory entries
255  */
256 static int
257 pfs_iterate(struct pfs_info *pi, struct pfs_node **pn, struct proc **p)
258 {
259 	if ((*pn)->pn_type == pfstype_none)
260 		return (-1);
261 
262 	if ((*pn)->pn_type != pfstype_procdir)
263 		++*pn;
264 
265 	while ((*pn)->pn_type == pfstype_procdir) {
266 		if (*p == NULL)
267 			*p = LIST_FIRST(&allproc);
268 		else
269 			*p = LIST_NEXT(*p, p_list);
270 		if (*p != NULL)
271 			return (0);
272 		++*pn;
273 	}
274 
275 	if ((*pn)->pn_type == pfstype_none)
276 		return (-1);
277 
278 	return (0);
279 }
280 
281 /*
282  * Return directory entries.
283  */
284 static int
285 pfs_readdir(struct vop_readdir_args *va)
286 {
287 	struct vnode *vn = va->a_vp;
288 	struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
289 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
290 	struct pfs_node *pd = pvd->pvd_pn;
291 	struct pfs_node *pn;
292 	struct dirent entry;
293 	struct uio *uio;
294 	struct proc *p;
295 	off_t offset;
296 	int error, i, resid;
297 
298 	if (vn->v_type != VDIR)
299 		return (ENOTDIR);
300 	uio = va->a_uio;
301 
302 	/* only allow reading entire entries */
303 	offset = uio->uio_offset;
304 	resid = uio->uio_resid;
305 	if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
306 		return (EINVAL);
307 
308 	/* skip unwanted entries */
309 	sx_slock(&allproc_lock);
310 	for (pn = pd->pn_nodes, p = NULL; offset > 0; offset -= PFS_DELEN)
311 		if (pfs_iterate(pi, &pn, &p) == -1)
312 			break;
313 
314 	/* fill in entries */
315 	entry.d_reclen = PFS_DELEN;
316 	while (pfs_iterate(pi, &pn, &p) != -1 && resid > 0) {
317 		if (!pn->pn_parent)
318 			pn->pn_parent = pd;
319 		if (!pn->pn_fileno)
320 			pfs_fileno_alloc(pi, pn);
321 		if (pvd->pvd_pid != NO_PID)
322 			entry.d_fileno = pn->pn_fileno * NO_PID + pvd->pvd_pid;
323 		else
324 			entry.d_fileno = pn->pn_fileno;
325 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
326 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
327 			entry.d_name[i] = pn->pn_name[i];
328 		entry.d_name[i] = 0;
329 		entry.d_namlen = i;
330 		switch (pn->pn_type) {
331 		case pfstype_procdir:
332 			KASSERT(p != NULL,
333 			    ("reached procdir node with p == NULL"));
334 			entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
335 			entry.d_namlen = snprintf(entry.d_name,
336 			    PFS_NAMELEN, "%d", p->p_pid);
337 			/* fall through */
338 		case pfstype_root:
339 		case pfstype_dir:
340 		case pfstype_this:
341 		case pfstype_parent:
342 			entry.d_type = DT_DIR;
343 			break;
344 		case pfstype_file:
345 			entry.d_type = DT_REG;
346 			break;
347 		case pfstype_symlink:
348 			entry.d_type = DT_LNK;
349 			break;
350 		default:
351 			sx_sunlock(&allproc_lock);
352 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
353 		}
354 		if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) {
355 			sx_sunlock(&allproc_lock);
356 			return (error);
357 		}
358 		offset += PFS_DELEN;
359 		resid -= PFS_DELEN;
360 	}
361 
362 	sx_sunlock(&allproc_lock);
363 	uio->uio_offset += offset;
364 	return (0);
365 }
366 
367 /*
368  * Read a symbolic link
369  */
370 static int
371 pfs_readlink(struct vop_readlink_args *va)
372 {
373 	struct vnode *vn = va->a_vp;
374 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
375 	struct pfs_node *pn = pvd->pvd_pn;
376 	struct uio *uio = va->a_uio;
377 	struct proc *proc = NULL;
378 	char buf[MAXPATHLEN], *ps;
379 	struct sbuf sb;
380 	int error, xlen;
381 
382 	if (vn->v_type != VLNK)
383 		return (EINVAL);
384 
385 	if (pvd->pvd_pid != NO_PID) {
386 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
387 			return (EIO);
388 		_PHOLD(proc);
389 		PROC_UNLOCK(proc);
390 	}
391 
392 	/* sbuf_new() can't fail with a static buffer */
393 	sbuf_new(&sb, buf, sizeof buf, 0);
394 
395 	error = (pn->pn_func)(curproc, proc, pn, &sb);
396 
397 	if (proc != NULL)
398 		PRELE(proc);
399 
400 	if (error) {
401 		sbuf_delete(&sb);
402 		return (error);
403 	}
404 
405 	/* XXX we should detect and handle overflows */
406 	sbuf_finish(&sb);
407 	ps = sbuf_data(&sb) + uio->uio_offset;
408 	xlen = sbuf_len(&sb) - uio->uio_offset;
409 	xlen = imin(xlen, uio->uio_resid);
410 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
411 	sbuf_delete(&sb);
412 	return (error);
413 }
414 
415 /*
416  * Reclaim a vnode
417  */
418 static int
419 pfs_reclaim(struct vop_reclaim_args *va)
420 {
421 	return (pfs_vncache_free(va->a_vp));
422 }
423 
424 /*
425  * Set attributes
426  */
427 static int
428 pfs_setattr(struct vop_setattr_args *va)
429 {
430 	if (va->a_vap->va_flags != (u_long)VNOVAL)
431 		return (EOPNOTSUPP);
432 	/* XXX it's a bit more complex than that, really... */
433 	return (0);
434 }
435 
436 /*
437  * Dummy operations
438  */
439 static int pfs_erofs(void *va)		{ return (EROFS); }
440 #if 0
441 static int pfs_null(void *va)		{ return (0); }
442 #endif
443 
444 /*
445  * Vnode operations
446  */
447 vop_t **pfs_vnodeop_p;
448 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
449 	{ &vop_default_desc,		(vop_t *)vop_defaultop	},
450 	{ &vop_access_desc,		(vop_t *)pfs_access	},
451 	{ &vop_close_desc,		(vop_t *)pfs_close	},
452 	{ &vop_create_desc,		(vop_t *)pfs_erofs	},
453 	{ &vop_getattr_desc,		(vop_t *)pfs_getattr	},
454 	{ &vop_link_desc,		(vop_t *)pfs_erofs	},
455 	{ &vop_lookup_desc,		(vop_t *)pfs_lookup	},
456 	{ &vop_mkdir_desc,		(vop_t *)pfs_erofs	},
457 	{ &vop_open_desc,		(vop_t *)pfs_open	},
458 	{ &vop_read_desc,		(vop_t *)pfs_read	},
459 	{ &vop_readdir_desc,		(vop_t *)pfs_readdir	},
460 	{ &vop_readlink_desc,		(vop_t *)pfs_readlink	},
461 	{ &vop_reclaim_desc,		(vop_t *)pfs_reclaim	},
462 	{ &vop_remove_desc,		(vop_t *)pfs_erofs	},
463 	{ &vop_rename_desc,		(vop_t *)pfs_erofs	},
464 	{ &vop_rmdir_desc,		(vop_t *)pfs_erofs	},
465 	{ &vop_setattr_desc,		(vop_t *)pfs_setattr	},
466 	{ &vop_symlink_desc,		(vop_t *)pfs_erofs	},
467 	{ &vop_write_desc,		(vop_t *)pfs_erofs	},
468 	/* XXX I've probably forgotten a few that need pfs_erofs */
469 	{ NULL,				(vop_t *)NULL		}
470 };
471 
472 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
473 	{ &pfs_vnodeop_p, pfs_vnodeop_entries };
474 
475 VNODEOP_SET(pfs_vnodeop_opv_desc);
476 
477