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