static void /*ARGSUSED*/ pty_getvattr(struct mount *mp, struct lwp *l, struct vattr *vattr) { vattr_null(vattr); /* get real uid */ vattr->va_uid = kauth_cred_getuid(l->l_cred); vattr->va_gid = TTY_GID; vattr->va_mode = TTY_PERM; }
/* * Invent attributes for ptyfsnode (vp) and store * them in (vap). * Directories lengths are returned as zero since * any real length would require the genuine size * to be computed, and nothing cares anyway. * * this is relatively minimal for ptyfs. */ int ptyfs_getattr(void *v) { struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *ap = v; struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp); struct vattr *vap = ap->a_vap; PTYFS_ITIMES(ptyfs, NULL, NULL, NULL); /* start by zeroing out the attributes */ vattr_null(vap); /* next do all the common fields */ vap->va_type = ap->a_vp->v_type; vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; vap->va_fileid = ptyfs->ptyfs_fileno; vap->va_gen = 0; vap->va_flags = 0; vap->va_blocksize = PAGE_SIZE; vap->va_atime = ptyfs->ptyfs_atime; vap->va_mtime = ptyfs->ptyfs_mtime; vap->va_ctime = ptyfs->ptyfs_ctime; vap->va_birthtime = ptyfs->ptyfs_birthtime; vap->va_mode = ptyfs->ptyfs_mode; vap->va_flags = ptyfs->ptyfs_flags; vap->va_uid = ptyfs->ptyfs_uid; vap->va_gid = ptyfs->ptyfs_gid; switch (ptyfs->ptyfs_type) { case PTYFSpts: case PTYFSptc: if (pty_isfree(ptyfs->ptyfs_pty, 1)) return ENOENT; vap->va_bytes = vap->va_size = 0; vap->va_rdev = ap->a_vp->v_rdev; vap->va_nlink = 1; break; case PTYFSroot: vap->va_rdev = 0; vap->va_bytes = vap->va_size = DEV_BSIZE; vap->va_nlink = 2; break; default: return EOPNOTSUPP; } return 0; }
static int puffs_vnop_getattr(struct vop_getattr_args *ap) { PUFFS_MSG_VARS(vn, getattr); struct vnode *vp = ap->a_vp; struct mount *mp = vp->v_mount; struct puffs_mount *pmp = MPTOPUFFSMP(mp); struct vattr *vap, *rvap; struct puffs_node *pn = VPTOPP(vp); int error = 0; if (vp->v_type == VBLK || vp->v_type == VCHR) return ENOTSUP; vap = ap->a_vap; PUFFS_MSG_ALLOC(vn, getattr); vattr_null(&getattr_msg->pvnr_va); puffs_credcvt(&getattr_msg->pvnr_cred, curproc->p_ucred); puffs_msg_setinfo(park_getattr, PUFFSOP_VN, PUFFS_VN_GETATTR, VPTOPNC(vp)); PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error); error = checkerr(pmp, error, __func__); if (error) goto out; rvap = &getattr_msg->pvnr_va; (void) memcpy(vap, rvap, sizeof(struct vattr)); vap->va_fsid = mp->mnt_stat.f_fsid.val[0]; if (pn->pn_stat & PNODE_METACACHE_ATIME) vap->va_atime = pn->pn_mc_atime; if (pn->pn_stat & PNODE_METACACHE_CTIME) vap->va_ctime = pn->pn_mc_ctime; if (pn->pn_stat & PNODE_METACACHE_MTIME) vap->va_mtime = pn->pn_mc_mtime; if (pn->pn_stat & PNODE_METACACHE_SIZE) { vap->va_size = pn->pn_mc_size; } else { if (rvap->va_size != VNOVAL && vp->v_type != VBLK && vp->v_type != VCHR) { pn->pn_serversize = rvap->va_size; if (vp->v_type == VREG) puffs_meta_setsize(vp, rvap->va_size, 0); } } out: PUFFS_MSG_RELEASE(getattr); return error; }
static void zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode, uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid) { vattr_null(vap); vap->va_mask = (uint_t)mask; if (mask & AT_TYPE) vap->va_type = IFTOVT(mode); if (mask & AT_MODE) vap->va_mode = mode & MODEMASK; if (mask & AT_UID) vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid; if (mask & AT_GID) vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid; vap->va_rdev = zfs_cmpldev(rdev); vap->va_nodeid = nodeid; }
static void fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat, uint64_t nodeid, enum vtype vtyp) { int i; fvdat->nid = nodeid; vattr_null(&fvdat->cached_attrs); if (nodeid == FUSE_ROOT_ID) { vp->v_vflag |= VV_ROOT; } vp->v_type = vtyp; vp->v_data = fvdat; for (i = 0; i < FUFH_MAXTYPE; i++) fvdat->fufh[i].fh_type = FUFH_INVALID; atomic_add_acq_int(&fuse_node_count, 1); }
static int flushvncache(struct vnode *vp, int waitfor) { struct puffs_node *pn = VPTOPP(vp); struct vattr va; int error = 0; /* flush out information from our metacache, see vop_setattr */ if (pn->pn_stat & PNODE_METACACHE_MASK && (pn->pn_stat & PNODE_DYING) == 0) { vattr_null(&va); error = dosetattr(vp, &va, FSCRED, SETATTR_CHSIZE | (waitfor == MNT_NOWAIT ? 0 : SETATTR_ASYNC)); if (error) return error; } /* * flush pages to avoid being overly dirty */ vfsync(vp, waitfor, 0, NULL, NULL); return error; }
int adosfs_getattr(void *v) { struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *sp = v; struct vattr *vap; struct adosfsmount *amp; struct anode *ap; u_long fblks; #ifdef ADOSFS_DIAGNOSTIC advopprint(sp); #endif vap = sp->a_vap; ap = VTOA(sp->a_vp); amp = ap->amp; vattr_null(vap); vap->va_uid = ap->uid; vap->va_gid = ap->gid; vap->va_fsid = sp->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; vap->va_atime.tv_sec = vap->va_mtime.tv_sec = vap->va_ctime.tv_sec = ap->mtime.days * 24 * 60 * 60 + ap->mtime.mins * 60 + ap->mtime.ticks / 50 + (8 * 365 + 2) * 24 * 60 * 60; vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec = vap->va_ctime.tv_nsec = 0; vap->va_gen = 0; vap->va_flags = 0; vap->va_rdev = NODEV; vap->va_fileid = ap->block; vap->va_type = sp->a_vp->v_type; vap->va_mode = adunixprot(ap->adprot) & amp->mask; if (sp->a_vp->v_type == VDIR) { vap->va_nlink = 1; /* XXX bogus, oh well */ vap->va_bytes = amp->bsize; vap->va_size = amp->bsize; } else { /* * XXX actually we can track this if we were to walk the list * of links if it exists. * XXX for now, just set nlink to 2 if this is a hard link * to a file, or a file with a hard link. */ vap->va_nlink = 1 + (ap->linkto != 0); /* * round up to nearest blocks add number of file list * blocks needed and mutiply by number of bytes per block. */ fblks = howmany(ap->fsize, amp->dbsize); fblks += howmany(fblks, ANODENDATBLKENT(ap)); vap->va_bytes = fblks * amp->dbsize; vap->va_size = ap->fsize; vap->va_blocksize = amp->dbsize; } #ifdef ADOSFS_DIAGNOSTIC printf(" 0)"); #endif return(0); }
/* * Routine: macx_swapon * Function: * Syscall interface to add a file to backing store */ int macx_swapon( char *filename, int flags, long size, long priority) { struct vnode *vp = 0; struct nameidata nd, *ndp; struct proc *p = current_proc(); pager_file_t pf; register int error; kern_return_t kr; mach_port_t backing_store; memory_object_default_t default_pager; int i; boolean_t funnel_state; struct vattr vattr; AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPON); AUDIT_ARG(value, priority); funnel_state = thread_funnel_set(kernel_flock, TRUE); ndp = &nd; if ((error = suser(p->p_ucred, &p->p_acflag))) goto swapon_bailout; if(default_pager_init_flag == 0) { start_def_pager(NULL); default_pager_init_flag = 1; } /* * Get a vnode for the paging area. */ NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE, filename, p); if ((error = namei(ndp))) goto swapon_bailout; vp = ndp->ni_vp; if (vp->v_type != VREG) { error = EINVAL; VOP_UNLOCK(vp, 0, p); goto swapon_bailout; } UBCINFOCHECK("macx_swapon", vp); if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) { VOP_UNLOCK(vp, 0, p); goto swapon_bailout; } if (vattr.va_size < (u_quad_t)size) { vattr_null(&vattr); vattr.va_size = (u_quad_t)size; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); if (error) { VOP_UNLOCK(vp, 0, p); goto swapon_bailout; } } /* add new backing store to list */ i = 0; while(bs_port_table[i].vp != 0) { if(i == MAX_BACKING_STORE) break; i++; } if(i == MAX_BACKING_STORE) { error = ENOMEM; VOP_UNLOCK(vp, 0, p); goto swapon_bailout; } /* remember the vnode. This vnode has namei() reference */ bs_port_table[i].vp = vp; /* * Look to see if we are already paging to this file. */ /* make certain the copy send of kernel call will work */ default_pager = MEMORY_OBJECT_DEFAULT_NULL; kr = host_default_memory_manager(host_priv_self(), &default_pager, 0); if(kr != KERN_SUCCESS) { error = EAGAIN; VOP_UNLOCK(vp, 0, p); bs_port_table[i].vp = 0; goto swapon_bailout; } kr = default_pager_backing_store_create(default_pager, -1, /* default priority */ 0, /* default cluster size */ &backing_store); memory_object_default_deallocate(default_pager); if(kr != KERN_SUCCESS) { error = ENOMEM; VOP_UNLOCK(vp, 0, p); bs_port_table[i].vp = 0; goto swapon_bailout; } /* * NOTE: we are able to supply PAGE_SIZE here instead of * an actual record size or block number because: * a: we do not support offsets from the beginning of the * file (allowing for non page size/record modulo offsets. * b: because allow paging will be done modulo page size */ VOP_UNLOCK(vp, 0, p); kr = default_pager_add_file(backing_store, vp, PAGE_SIZE, ((int)vattr.va_size)/PAGE_SIZE); if(kr != KERN_SUCCESS) { bs_port_table[i].vp = 0; if(kr == KERN_INVALID_ARGUMENT) error = EINVAL; else error = ENOMEM; goto swapon_bailout; } bs_port_table[i].bs = (void *)backing_store; error = 0; if (!ubc_hold(vp)) panic("macx_swapon: hold"); /* Mark this vnode as being used for swapfile */ SET(vp->v_flag, VSWAP); ubc_setcred(vp, p); /* * take an extra reference on the vnode to keep * vnreclaim() away from this vnode. */ VREF(vp); /* Hold on to the namei reference to the paging file vnode */ vp = 0; swapon_bailout: if (vp) { vrele(vp); } (void) thread_funnel_set(kernel_flock, FALSE); AUDIT_MACH_SYSCALL_EXIT(error); return(error); }
/* * Common code for vnode open operations. * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. */ int vn_open(struct nameidata *ndp, int fmode, int cmode) { struct vnode *vp; struct lwp *l = curlwp; kauth_cred_t cred = l->l_cred; struct vattr va; int error; const char *pathstring; if ((fmode & (O_CREAT | O_DIRECTORY)) == (O_CREAT | O_DIRECTORY)) return EINVAL; ndp->ni_cnd.cn_flags &= TRYEMULROOT | NOCHROOT; if (fmode & O_CREAT) { ndp->ni_cnd.cn_nameiop = CREATE; ndp->ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF; if ((fmode & O_EXCL) == 0 && ((fmode & O_NOFOLLOW) == 0)) ndp->ni_cnd.cn_flags |= FOLLOW; } else { ndp->ni_cnd.cn_nameiop = LOOKUP; ndp->ni_cnd.cn_flags |= LOCKLEAF; if ((fmode & O_NOFOLLOW) == 0) ndp->ni_cnd.cn_flags |= FOLLOW; } pathstring = pathbuf_stringcopy_get(ndp->ni_pathbuf); if (pathstring == NULL) { return ENOMEM; } error = namei(ndp); if (error) goto out; vp = ndp->ni_vp; #if NVERIEXEC > 0 error = veriexec_openchk(l, ndp->ni_vp, pathstring, fmode); if (error) goto bad; #endif /* NVERIEXEC > 0 */ if (fmode & O_CREAT) { if (ndp->ni_vp == NULL) { vattr_null(&va); va.va_type = VREG; va.va_mode = cmode; if (fmode & O_EXCL) va.va_vaflags |= VA_EXCLUSIVE; error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &va); vput(ndp->ni_dvp); if (error) goto out; fmode &= ~O_TRUNC; vp = ndp->ni_vp; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } else { VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); ndp->ni_dvp = NULL; vp = ndp->ni_vp; if (fmode & O_EXCL) { error = EEXIST; goto bad; } fmode &= ~O_CREAT; } } else { vp = ndp->ni_vp; } if (vp->v_type == VSOCK) { error = EOPNOTSUPP; goto bad; } if (ndp->ni_vp->v_type == VLNK) { error = EFTYPE; goto bad; } if ((fmode & O_CREAT) == 0) { error = vn_openchk(vp, cred, fmode); if (error != 0) goto bad; } if (fmode & O_TRUNC) { vattr_null(&va); va.va_size = 0; error = VOP_SETATTR(vp, &va, cred); if (error != 0) goto bad; } if ((error = VOP_OPEN(vp, fmode, cred)) != 0) goto bad; if (fmode & FWRITE) { mutex_enter(vp->v_interlock); vp->v_writecount++; mutex_exit(vp->v_interlock); } bad: if (error) vput(vp); out: pathbuf_stringcopy_put(ndp->ni_pathbuf, pathstring); return (error); }
/* * Dump core, into a file named "progname.core" or "core" (depending on the * value of shortcorename), unless the process was setuid/setgid. */ static int coredump(struct lwp *l, const char *pattern) { struct vnode *vp; struct proc *p; struct vmspace *vm; kauth_cred_t cred; struct pathbuf *pb; struct nameidata nd; struct vattr vattr; struct coredump_iostate io; struct plimit *lim; int error, error1; char *name, *lastslash; name = PNBUF_GET(); p = l->l_proc; vm = p->p_vmspace; mutex_enter(proc_lock); /* p_session */ mutex_enter(p->p_lock); /* * Refuse to core if the data + stack + user size is larger than * the core dump limit. XXX THIS IS WRONG, because of mapped * data. */ if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >= p->p_rlimit[RLIMIT_CORE].rlim_cur) { error = EFBIG; /* better error code? */ mutex_exit(p->p_lock); mutex_exit(proc_lock); goto done; } /* * It may well not be curproc, so grab a reference to its current * credentials. */ kauth_cred_hold(p->p_cred); cred = p->p_cred; /* * Make sure the process has not set-id, to prevent data leaks, * unless it was specifically requested to allow set-id coredumps. */ if (p->p_flag & PK_SUGID) { if (!security_setidcore_dump) { error = EPERM; mutex_exit(p->p_lock); mutex_exit(proc_lock); goto done; } pattern = security_setidcore_path; } /* Lock, as p_limit and pl_corename might change. */ lim = p->p_limit; mutex_enter(&lim->pl_lock); if (pattern == NULL) { pattern = lim->pl_corename; } error = coredump_buildname(p, name, pattern, MAXPATHLEN); mutex_exit(&lim->pl_lock); if (error) { mutex_exit(p->p_lock); mutex_exit(proc_lock); goto done; } /* * On a simple filename, see if the filesystem allow us to write * core dumps there. */ lastslash = strrchr(name, '/'); if (!lastslash) { vp = p->p_cwdi->cwdi_cdir; if (vp->v_mount == NULL || (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0) error = EPERM; } mutex_exit(p->p_lock); mutex_exit(proc_lock); if (error) goto done; /* * On a complex filename, see if the filesystem allow us to write * core dumps there. * * XXX: We should have an API that avoids double lookups */ if (lastslash) { char c[2]; if (lastslash - name >= MAXPATHLEN - 2) { error = EPERM; goto done; } c[0] = lastslash[1]; c[1] = lastslash[2]; lastslash[1] = '.'; lastslash[2] = '\0'; error = namei_simple_kernel(name, NSM_FOLLOW_NOEMULROOT, &vp); if (error) goto done; if (vp->v_mount == NULL || (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0) error = EPERM; vrele(vp); if (error) goto done; lastslash[1] = c[0]; lastslash[2] = c[1]; } pb = pathbuf_create(name); if (pb == NULL) { error = ENOMEM; goto done; } NDINIT(&nd, LOOKUP, NOFOLLOW, pb); if ((error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE, S_IRUSR | S_IWUSR)) != 0) { pathbuf_destroy(pb); goto done; } vp = nd.ni_vp; pathbuf_destroy(pb); /* * Don't dump to: * - non-regular files * - files with links * - files we don't own */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) || vattr.va_nlink != 1 || vattr.va_uid != kauth_cred_geteuid(cred)) { error = EACCES; goto out; } vattr_null(&vattr); vattr.va_size = 0; if ((p->p_flag & PK_SUGID) && security_setidcore_dump) { vattr.va_uid = security_setidcore_owner; vattr.va_gid = security_setidcore_group; vattr.va_mode = security_setidcore_mode; } VOP_SETATTR(vp, &vattr, cred); p->p_acflag |= ACORE; io.io_lwp = l; io.io_vp = vp; io.io_cred = cred; io.io_offset = 0; /* Now dump the actual core file. */ error = (*p->p_execsw->es_coredump)(l, &io); out: VOP_UNLOCK(vp); error1 = vn_close(vp, FWRITE, cred); if (error == 0) error = error1; done: if (name != NULL) PNBUF_PUT(name); return error; }
/* Register a new filesystem type in the global table */ static int vfs_register(struct vfsconf *vfc) { struct sysctl_oid *oidp; struct vfsops *vfsops; static int once; if (!once) { vattr_null(&va_null); once = 1; } if (vfc->vfc_version != VFS_VERSION) { printf("ERROR: filesystem %s, unsupported ABI version %x\n", vfc->vfc_name, vfc->vfc_version); return (EINVAL); } if (vfs_byname(vfc->vfc_name) != NULL) return EEXIST; vfc->vfc_typenum = maxvfsconf++; TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); /* * If this filesystem has a sysctl node under vfs * (i.e. vfs.xxfs), then change the oid number of that node to * match the filesystem's type number. This allows user code * which uses the type number to read sysctl variables defined * by the filesystem to continue working. Since the oids are * in a sorted list, we need to make sure the order is * preserved by re-registering the oid after modifying its * number. */ sysctl_lock(); SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { sysctl_unregister_oid(oidp); oidp->oid_number = vfc->vfc_typenum; sysctl_register_oid(oidp); break; } sysctl_unlock(); /* * Initialise unused ``struct vfsops'' fields, to use * the vfs_std*() functions. Note, we need the mount * and unmount operations, at the least. The check * for vfsops available is just a debugging aid. */ KASSERT(vfc->vfc_vfsops != NULL, ("Filesystem %s has no vfsops", vfc->vfc_name)); /* * Check the mount and unmount operations. */ vfsops = vfc->vfc_vfsops; KASSERT(vfsops->vfs_mount != NULL, ("Filesystem %s has no mount op", vfc->vfc_name)); KASSERT(vfsops->vfs_unmount != NULL, ("Filesystem %s has no unmount op", vfc->vfc_name)); if (vfsops->vfs_root == NULL) /* return file system's root vnode */ vfsops->vfs_root = vfs_stdroot; if (vfsops->vfs_quotactl == NULL) /* quota control */ vfsops->vfs_quotactl = vfs_stdquotactl; if (vfsops->vfs_statfs == NULL) /* return file system's status */ vfsops->vfs_statfs = vfs_stdstatfs; if (vfsops->vfs_sync == NULL) /* * flush unwritten data (nosync) * file systems can use vfs_stdsync * explicitly by setting it in the * vfsop vector. */ vfsops->vfs_sync = vfs_stdnosync; if (vfsops->vfs_vget == NULL) /* convert an inode number to a vnode */ vfsops->vfs_vget = vfs_stdvget; if (vfsops->vfs_fhtovp == NULL) /* turn an NFS file handle into a vnode */ vfsops->vfs_fhtovp = vfs_stdfhtovp; if (vfsops->vfs_checkexp == NULL) /* check if file system is exported */ vfsops->vfs_checkexp = vfs_stdcheckexp; if (vfsops->vfs_init == NULL) /* file system specific initialisation */ vfsops->vfs_init = vfs_stdinit; if (vfsops->vfs_uninit == NULL) /* file system specific uninitialisation */ vfsops->vfs_uninit = vfs_stduninit; if (vfsops->vfs_extattrctl == NULL) /* extended attribute control */ vfsops->vfs_extattrctl = vfs_stdextattrctl; if (vfsops->vfs_sysctl == NULL) vfsops->vfs_sysctl = vfs_stdsysctl; /* * Call init function for this VFS... */ (*(vfc->vfc_vfsops->vfs_init))(vfc); return 0; }