summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_generic.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-07-08 20:12:14 +0000
committerjhb <jhb@FreeBSD.org>2006-07-08 20:12:14 +0000
commit094306d69d41989862ff128380df0e7e2bdbe80d (patch)
tree08f1122008ef638646627d52e5fc05db3ffc64ba /sys/kern/sys_generic.c
parent28bb163264ff66e4b22bed304a675e7ab2ca723a (diff)
downloadFreeBSD-src-094306d69d41989862ff128380df0e7e2bdbe80d.zip
FreeBSD-src-094306d69d41989862ff128380df0e7e2bdbe80d.tar.gz
- Split ioctl() up into ioctl() and kern_ioctl(). The kern_ioctl() assumes
that the 'data' pointer is already setup to point to a valid KVM buffer or contains the copied-in data from userland as appropriate (ioctl(2) still does this). kern_ioctl() takes care of looking up a file pointer, implementing FIONCLEX and FIOCLEX, and calling fi_ioctl(). - Use kern_ioctl() to implement xenix_rdchk() instead of using the stackgap and mark xenix_rdchk() MPSAFE.
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r--sys/kern/sys_generic.c81
1 files changed, 44 insertions, 37 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index e8cb5e9..13387ec 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -523,13 +523,10 @@ struct ioctl_args {
int
ioctl(struct thread *td, struct ioctl_args *uap)
{
- struct file *fp;
- struct filedesc *fdp;
u_long com;
- int error = 0;
+ int error;
u_int size;
caddr_t data, memp;
- int tmp;
if (uap->com > 0xffffffff) {
printf(
@@ -537,27 +534,7 @@ ioctl(struct thread *td, struct ioctl_args *uap)
td->td_proc->p_pid, td->td_proc->p_comm, uap->com);
uap->com &= 0xffffffff;
}
- if ((error = fget(td, uap->fd, &fp)) != 0)
- return (error);
- if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
- fdrop(fp, td);
- return (EBADF);
- }
- fdp = td->td_proc->p_fd;
- switch (com = uap->com) {
- case FIONCLEX:
- FILEDESC_LOCK_FAST(fdp);
- fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
- FILEDESC_UNLOCK_FAST(fdp);
- fdrop(fp, td);
- return (0);
- case FIOCLEX:
- FILEDESC_LOCK_FAST(fdp);
- fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
- FILEDESC_UNLOCK_FAST(fdp);
- fdrop(fp, td);
- return (0);
- }
+ com = uap->com;
/*
* Interpret high order word to find amount of data to be
@@ -571,10 +548,8 @@ ioctl(struct thread *td, struct ioctl_args *uap)
#else
((com & (IOC_IN | IOC_OUT)) && size == 0) ||
#endif
- ((com & IOC_VOID) && size > 0)) {
- fdrop(fp, td);
+ ((com & IOC_VOID) && size > 0))
return (ENOTTY);
- }
if (size > 0) {
memp = malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
@@ -587,7 +562,6 @@ ioctl(struct thread *td, struct ioctl_args *uap)
error = copyin(uap->data, data, (u_int)size);
if (error) {
free(memp, M_IOCTLOPS);
- fdrop(fp, td);
return (error);
}
} else if (com & IOC_OUT) {
@@ -598,7 +572,43 @@ ioctl(struct thread *td, struct ioctl_args *uap)
bzero(data, size);
}
- if (com == FIONBIO) {
+ error = kern_ioctl(td, uap->fd, com, data);
+
+ if (error == 0 && (com & IOC_OUT))
+ error = copyout(data, uap->data, (u_int)size);
+
+ if (memp != NULL)
+ free(memp, M_IOCTLOPS);
+ return (error);
+}
+
+int
+kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
+{
+ struct file *fp;
+ struct filedesc *fdp;
+ int error;
+ int tmp;
+
+ if ((error = fget(td, fd, &fp)) != 0)
+ return (error);
+ if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
+ fdrop(fp, td);
+ return (EBADF);
+ }
+ fdp = td->td_proc->p_fd;
+ switch (com) {
+ case FIONCLEX:
+ FILEDESC_LOCK_FAST(fdp);
+ fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
+ FILEDESC_UNLOCK_FAST(fdp);
+ goto out;
+ case FIOCLEX:
+ FILEDESC_LOCK_FAST(fdp);
+ fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
+ FILEDESC_UNLOCK_FAST(fdp);
+ goto out;
+ case FIONBIO:
FILE_LOCK(fp);
if ((tmp = *(int *)data))
fp->f_flag |= FNONBLOCK;
@@ -606,7 +616,8 @@ ioctl(struct thread *td, struct ioctl_args *uap)
fp->f_flag &= ~FNONBLOCK;
FILE_UNLOCK(fp);
data = (void *)&tmp;
- } else if (com == FIOASYNC) {
+ break;
+ case FIOASYNC:
FILE_LOCK(fp);
if ((tmp = *(int *)data))
fp->f_flag |= FASYNC;
@@ -614,15 +625,11 @@ ioctl(struct thread *td, struct ioctl_args *uap)
fp->f_flag &= ~FASYNC;
FILE_UNLOCK(fp);
data = (void *)&tmp;
+ break;
}
error = fo_ioctl(fp, com, data, td->td_ucred, td);
-
- if (error == 0 && (com & IOC_OUT))
- error = copyout(data, uap->data, (u_int)size);
-
- if (memp != NULL)
- free(memp, M_IOCTLOPS);
+out:
fdrop(fp, td);
return (error);
}
OpenPOWER on IntegriCloud