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.
This commit is contained in:
Ian Dowse 2002-09-02 22:24:14 +00:00
parent b168ce8b63
commit 49c2ff159f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=102868
2 changed files with 86 additions and 67 deletions

View File

@ -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>
@ -252,14 +253,48 @@ int
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;
flp = (struct flock *)arg;
if (flp->l_whence == SEEK_CUR) {
if (fp->f_offset < 0 ||
(flp->l_start > 0 &&
fp->f_offset > OFF_MAX - flp->l_start)) {
FILEDESC_UNLOCK(fdp);
error = EOVERFLOW;
break;
}
flp->l_start += fp->f_offset;
}
/*
* copyin/lockop may block
* 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) {
if (fp->f_offset < 0 ||
(fl.l_start > 0 &&
fp->f_offset > OFF_MAX - fl.l_start)) {
fdrop(fp, td);
error = EOVERFLOW;
break;
}
fl.l_start += fp->f_offset;
}
switch (fl.l_type) {
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;
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 (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;
}
flp->l_start += fp->f_offset;
}
/*
* copyin/lockop may block
* 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);
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);
error = EOVERFLOW;
break;
}
fl.l_start += fp->f_offset;
}
error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK,
&fl, F_POSIX);
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);

View File

@ -38,6 +38,7 @@ int kern_chmod(struct thread *td, char *path, enum uio_seg pathseg,
int mode);
int kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
int gid);
int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
int kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,