summaryrefslogtreecommitdiff
path: root/sys/kern/vfs_syscalls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r--sys/kern/vfs_syscalls.c247
1 files changed, 246 insertions, 1 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index dca9f9033d6..caec7dbdf3f 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_syscalls.c,v 1.61 2000/02/01 04:03:14 assar Exp $ */
+/* $OpenBSD: vfs_syscalls.c,v 1.62 2000/02/07 04:55:19 assar Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
/*
@@ -948,6 +948,251 @@ sys_open(p, v, retval)
}
/*
+ * Get file handle system call
+ */
+int
+sys_getfh(p, v, retval)
+ struct proc *p;
+ register void *v;
+ register_t *retval;
+{
+ register struct sys_getfh_args /* {
+ syscallarg(char *) fname;
+ syscallarg(fhandle_t *) fhp;
+ } */ *uap = v;
+ register struct vnode *vp;
+ fhandle_t fh;
+ int error;
+ struct nameidata nd;
+
+ /*
+ * Must be super user
+ */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if(error)
+ return (error);
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
+ SCARG(uap, fname), p);
+ error = namei(&nd);
+ if (error)
+ return (error);
+ vp = nd.ni_vp;
+ bzero((caddr_t)&fh, sizeof(fh));
+ fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+ error = VFS_VPTOFH(vp, &fh.fh_fid);
+ vput(vp);
+ if (error)
+ return (error);
+ error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh));
+ return (error);
+}
+
+/*
+ * Open a file given a file handle.
+ *
+ * Check permissions, allocate an open file structure,
+ * and call the device open routine if any.
+ */
+int
+sys_fhopen(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ register struct sys_fhopen_args /* {
+ syscallarg(const fhandle_t *) fhp;
+ syscallarg(int) flags;
+ } */ *uap = v;
+ struct filedesc *fdp = p->p_fd;
+ struct file *fp;
+ struct vnode *vp = NULL;
+ struct mount *mp;
+ struct ucred *cred = p->p_ucred;
+ int flags;
+ struct file *nfp;
+ int type, indx, error=0;
+ struct flock lf;
+ struct vattr va;
+ fhandle_t fh;
+
+ /*
+ * Must be super user
+ */
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return (error);
+
+ flags = FFLAGS(SCARG(uap, flags));
+ if ((flags & (FREAD | FWRITE)) == 0)
+ return (EINVAL);
+ if ((flags & O_CREAT))
+ return (EINVAL);
+
+ if ((error = falloc(p, &nfp, &indx)) != 0)
+ return (error);
+ fp = nfp;
+ if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
+ goto bad;
+
+ if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
+ error = ESTALE;
+ goto bad;
+ }
+
+ if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
+ vp = NULL; /* most likely unnecessary sanity for bad: */
+ goto bad;
+ }
+
+ /* Now do an effective vn_open */
+
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto bad;
+ }
+ if (flags & FREAD) {
+ if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
+ goto bad;
+ }
+ if (flags & (FWRITE | O_TRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto bad;
+ }
+ if ((error = vn_writechk(vp)) != 0 ||
+ (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
+ goto bad;
+ }
+ if (flags & O_TRUNC) {
+ VOP_UNLOCK(vp, 0, p); /* XXX */
+ VOP_LEASE(vp, p, cred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
+ VATTR_NULL(&va);
+ va.va_size = 0;
+ if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
+ goto bad;
+ }
+ if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
+ goto bad;
+ if (flags & FWRITE)
+ vp->v_writecount++;
+
+ /* done with modified vn_open, now finish what sys_open does. */
+
+ fp->f_flag = flags & FMASK;
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
+ fp->f_data = (caddr_t)vp;
+ if (flags & (O_EXLOCK | O_SHLOCK)) {
+ lf.l_whence = SEEK_SET;
+ lf.l_start = 0;
+ lf.l_len = 0;
+ if (flags & O_EXLOCK)
+ lf.l_type = F_WRLCK;
+ else
+ lf.l_type = F_RDLCK;
+ type = F_FLOCK;
+ if ((flags & FNONBLOCK) == 0)
+ type |= F_WAIT;
+ VOP_UNLOCK(vp, 0, p);
+ error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
+ if (error) {
+ (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
+ ffree(fp);
+ fdremove(fdp, indx);
+ return (error);
+ }
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ fp->f_flag |= FHASLOCK;
+ }
+ VOP_UNLOCK(vp, 0, p);
+ *retval = indx;
+ return (0);
+
+bad:
+ ffree(fp);
+ fdremove(fdp, indx);
+ if (vp != NULL)
+ vput(vp);
+ return (error);
+}
+
+/* ARGSUSED */
+int
+sys_fhstat(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ register struct sys_fhstat_args /* {
+ syscallarg(const fhandle_t *) fhp;
+ syscallarg(struct stat *) sb;
+ } */ *uap = v;
+ struct stat sb;
+ int error;
+ fhandle_t fh;
+ struct mount *mp;
+ struct vnode *vp;
+
+ /*
+ * Must be super user
+ */
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return (error);
+
+ if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
+ return (error);
+
+ if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
+ return (ESTALE);
+ if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
+ return (error);
+ error = vn_stat(vp, &sb, p);
+ vput(vp);
+ if (error)
+ return (error);
+ error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
+ return (error);
+}
+
+/* ARGSUSED */
+int
+sys_fhstatfs(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ register struct sys_fhstatfs_args /*
+ syscallarg(const fhandle_t *) fhp;
+ syscallarg(struct statfs *) buf;
+ } */ *uap = v;
+ struct statfs sp;
+ fhandle_t fh;
+ struct mount *mp;
+ struct vnode *vp;
+ int error;
+
+ /*
+ * Must be super user
+ */
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return (error);
+
+ if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
+ return (error);
+
+ if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
+ return (ESTALE);
+ if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
+ return (error);
+ mp = vp->v_mount;
+ vput(vp);
+ if ((error = VFS_STATFS(mp, &sp, p)) != 0)
+ return (error);
+ sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ return (copyout(&sp, SCARG(uap, buf), sizeof(sp)));
+}
+
+/*
* Create a special file.
*/
/* ARGSUSED */