summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_descrip.c
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2002-09-02 22:24:14 +0000
committeriedowse <iedowse@FreeBSD.org>2002-09-02 22:24:14 +0000
commit62f75e87a487b86c51a8b2ad6a92a74221098916 (patch)
tree6eca1d23ba3c4f72c309f662d4551124df89327e /sys/kern/kern_descrip.c
parent6068c024d6120ed43120c3f1f022738b3fadebe7 (diff)
downloadFreeBSD-src-62f75e87a487b86c51a8b2ad6a92a74221098916.zip
FreeBSD-src-62f75e87a487b86c51a8b2ad6a92a74221098916.tar.gz
Split fcntl() into a wrapper and a kernel-callable kern_fcntl()
implementation. The wrapper is responsible for copying additional structure arguments (struct flock) to and from userland.
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r--sys/kern/kern_descrip.c148
1 files changed, 83 insertions, 65 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index db4e4d4..5e31e95 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -46,6 +46,7 @@
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#include <sys/conf.h>
#include <sys/filedesc.h>
@@ -253,13 +254,47 @@ fcntl(td, uap)
struct thread *td;
register struct fcntl_args *uap;
{
+ struct flock fl;
+ intptr_t arg;
+ int error;
+
+ error = 0;
+ switch (uap->cmd) {
+ case F_SETLK:
+ case F_GETLK:
+ error = copyin((caddr_t)(intptr_t)uap->arg, &fl, sizeof(fl));
+ arg = (intptr_t)&fl;
+ break;
+ default:
+ arg = uap->arg;
+ break;
+ }
+ if (error)
+ return (error);
+
+ error = kern_fcntl(td, uap->fd, uap->cmd, arg);
+ if (error)
+ return (error);
+
+ switch (uap->cmd) {
+ case F_GETLK:
+ error = copyout(&fl, (caddr_t)(intptr_t)uap->arg, sizeof(fl));
+ break;
+ }
+
+ return (error);
+}
+
+int
+kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
+{
register struct proc *p = td->td_proc;
register struct filedesc *fdp;
register struct file *fp;
register char *pop;
struct vnode *vp;
+ struct flock *flp;
int i, tmp, error = 0, flg = F_POSIX;
- struct flock fl;
u_int newmin;
struct proc *leaderp;
@@ -267,17 +302,17 @@ fcntl(td, uap)
fdp = p->p_fd;
FILEDESC_LOCK(fdp);
- if ((unsigned)uap->fd >= fdp->fd_nfiles ||
- (fp = fdp->fd_ofiles[uap->fd]) == NULL) {
+ if ((unsigned)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL) {
FILEDESC_UNLOCK(fdp);
error = EBADF;
goto done2;
}
- pop = &fdp->fd_ofileflags[uap->fd];
+ pop = &fdp->fd_ofileflags[fd];
- switch (uap->cmd) {
+ switch (cmd) {
case F_DUPFD:
- newmin = uap->arg;
+ newmin = arg;
if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
newmin >= maxfilesperproc) {
FILEDESC_UNLOCK(fdp);
@@ -288,7 +323,7 @@ fcntl(td, uap)
FILEDESC_UNLOCK(fdp);
break;
}
- error = do_dup(fdp, uap->fd, i, td->td_retval, td);
+ error = do_dup(fdp, fd, i, td->td_retval, td);
break;
case F_GETFD:
@@ -298,7 +333,7 @@ fcntl(td, uap)
case F_SETFD:
*pop = (*pop &~ UF_EXCLOSE) |
- (uap->arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
+ (arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
FILEDESC_UNLOCK(fdp);
break;
@@ -313,7 +348,7 @@ fcntl(td, uap)
fhold(fp);
FILEDESC_UNLOCK(fdp);
fp->f_flag &= ~FCNTLFLAGS;
- fp->f_flag |= FFLAGS(uap->arg & ~O_ACCMODE) & FCNTLFLAGS;
+ fp->f_flag |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS;
tmp = fp->f_flag & FNONBLOCK;
error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
if (error) {
@@ -343,7 +378,7 @@ fcntl(td, uap)
case F_SETOWN:
fhold(fp);
FILEDESC_UNLOCK(fdp);
- error = fo_ioctl(fp, FIOSETOWN, &uap->arg, td->td_ucred, td);
+ error = fo_ioctl(fp, FIOSETOWN, &arg, td->td_ucred, td);
fdrop(fp, td);
break;
@@ -357,32 +392,26 @@ fcntl(td, uap)
error = EBADF;
break;
}
- vp = (struct vnode *)fp->f_data;
- /*
- * copyin/lockop may block
- */
- fhold(fp);
- FILEDESC_UNLOCK(fdp);
- vp = (struct vnode *)fp->f_data;
-
- /* Copy in the lock structure */
- error = copyin((caddr_t)(intptr_t)uap->arg, &fl, sizeof(fl));
- if (error) {
- fdrop(fp, td);
- break;
- }
- if (fl.l_whence == SEEK_CUR) {
+ flp = (struct flock *)arg;
+ if (flp->l_whence == SEEK_CUR) {
if (fp->f_offset < 0 ||
- (fl.l_start > 0 &&
- fp->f_offset > OFF_MAX - fl.l_start)) {
- fdrop(fp, td);
+ (flp->l_start > 0 &&
+ fp->f_offset > OFF_MAX - flp->l_start)) {
+ FILEDESC_UNLOCK(fdp);
error = EOVERFLOW;
break;
}
- fl.l_start += fp->f_offset;
+ flp->l_start += fp->f_offset;
}
- switch (fl.l_type) {
+ /*
+ * lockop may block
+ */
+ fhold(fp);
+ FILEDESC_UNLOCK(fdp);
+ vp = (struct vnode *)fp->f_data;
+
+ switch (flp->l_type) {
case F_RDLCK:
if ((fp->f_flag & FREAD) == 0) {
error = EBADF;
@@ -393,7 +422,7 @@ fcntl(td, uap)
leaderp = p->p_leader;
PROC_UNLOCK(p);
error = VOP_ADVLOCK(vp, (caddr_t)leaderp, F_SETLK,
- &fl, flg);
+ flp, flg);
break;
case F_WRLCK:
if ((fp->f_flag & FWRITE) == 0) {
@@ -404,15 +433,15 @@ fcntl(td, uap)
p->p_flag |= P_ADVLOCK;
leaderp = p->p_leader;
PROC_UNLOCK(p);
- error = VOP_ADVLOCK(vp, (caddr_t)leaderp, F_SETLK,
- &fl, flg);
+ error = VOP_ADVLOCK(vp, (caddr_t)leaderp, F_SETLK, flp,
+ flg);
break;
case F_UNLCK:
PROC_LOCK(p);
leaderp = p->p_leader;
PROC_UNLOCK(p);
- error = VOP_ADVLOCK(vp, (caddr_t)leaderp, F_UNLCK,
- &fl, F_POSIX);
+ error = VOP_ADVLOCK(vp, (caddr_t)leaderp, F_UNLCK, flp,
+ F_POSIX);
break;
default:
error = EINVAL;
@@ -427,44 +456,33 @@ fcntl(td, uap)
error = EBADF;
break;
}
- vp = (struct vnode *)fp->f_data;
- /*
- * copyin/lockop may block
- */
- fhold(fp);
- FILEDESC_UNLOCK(fdp);
- vp = (struct vnode *)fp->f_data;
-
- /* Copy in the lock structure */
- error = copyin((caddr_t)(intptr_t)uap->arg, &fl, sizeof(fl));
- if (error) {
- fdrop(fp, td);
- break;
- }
- if (fl.l_type != F_RDLCK && fl.l_type != F_WRLCK &&
- fl.l_type != F_UNLCK) {
- fdrop(fp, td);
+ flp = (struct flock *)arg;
+ if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK &&
+ flp->l_type != F_UNLCK) {
+ FILEDESC_UNLOCK(fdp);
error = EINVAL;
break;
}
- if (fl.l_whence == SEEK_CUR) {
- if ((fl.l_start > 0 &&
- fp->f_offset > OFF_MAX - fl.l_start) ||
- (fl.l_start < 0 &&
- fp->f_offset < OFF_MIN - fl.l_start)) {
- fdrop(fp, td);
+ if (flp->l_whence == SEEK_CUR) {
+ if ((flp->l_start > 0 &&
+ fp->f_offset > OFF_MAX - flp->l_start) ||
+ (flp->l_start < 0 &&
+ fp->f_offset < OFF_MIN - flp->l_start)) {
+ FILEDESC_UNLOCK(fdp);
error = EOVERFLOW;
break;
}
- fl.l_start += fp->f_offset;
+ flp->l_start += fp->f_offset;
}
- error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK,
- &fl, F_POSIX);
+ /*
+ * lockop may block
+ */
+ fhold(fp);
+ FILEDESC_UNLOCK(fdp);
+ vp = (struct vnode *)fp->f_data;
+ error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp,
+ F_POSIX);
fdrop(fp, td);
- if (error == 0) {
- error = copyout(&fl, (caddr_t)(intptr_t)uap->arg,
- sizeof(fl));
- }
break;
default:
FILEDESC_UNLOCK(fdp);
OpenPOWER on IntegriCloud