diff options
author | ru <ru@FreeBSD.org> | 2006-09-27 19:57:02 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2006-09-27 19:57:02 +0000 |
commit | 4ef62e4ca582414062d69e20a1ccdade4a110938 (patch) | |
tree | a886251dab8c19f71a5bfd0199ec1d9b327b3513 /sys/kern/sys_generic.c | |
parent | f6b387ce531fb4ba91958db5aadcb53f89d4ed1b (diff) | |
download | FreeBSD-src-4ef62e4ca582414062d69e20a1ccdade4a110938.zip FreeBSD-src-4ef62e4ca582414062d69e20a1ccdade4a110938.tar.gz |
Fix our ioctl(2) implementation when the argument is "int". New
ioctls passing integer arguments should use the _IOWINT() macro.
This fixes a lot of ioctl's not working on sparc64, most notable
being keyboard/syscons ioctls.
Full ABI compatibility is provided, with the bonus of fixing the
handling of old ioctls on sparc64.
Reviewed by: bde (with contributions)
Tested by: emax, marius
MFC after: 1 week
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r-- | sys/kern/sys_generic.c | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 13387ec..cab79b8 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -524,9 +524,9 @@ int ioctl(struct thread *td, struct ioctl_args *uap) { u_long com; - int error; + int arg, error; u_int size; - caddr_t data, memp; + caddr_t data; if (uap->com > 0xffffffff) { printf( @@ -548,20 +548,24 @@ ioctl(struct thread *td, struct ioctl_args *uap) #else ((com & (IOC_IN | IOC_OUT)) && size == 0) || #endif - ((com & IOC_VOID) && size > 0)) + ((com & IOC_VOID) && size > 0 && size != sizeof(int))) return (ENOTTY); if (size > 0) { - memp = malloc((u_long)size, M_IOCTLOPS, M_WAITOK); - data = memp; - } else { - memp = NULL; + if (!(com & IOC_VOID)) + data = malloc((u_long)size, M_IOCTLOPS, M_WAITOK); + else { + /* Integer argument. */ + arg = (intptr_t)uap->data; + data = (void *)&arg; + size = 0; + } + } else data = (void *)&uap->data; - } if (com & IOC_IN) { error = copyin(uap->data, data, (u_int)size); if (error) { - free(memp, M_IOCTLOPS); + free(data, M_IOCTLOPS); return (error); } } else if (com & IOC_OUT) { @@ -577,8 +581,8 @@ ioctl(struct thread *td, struct ioctl_args *uap) if (error == 0 && (com & IOC_OUT)) error = copyout(data, uap->data, (u_int)size); - if (memp != NULL) - free(memp, M_IOCTLOPS); + if (size > 0) + free(data, M_IOCTLOPS); return (error); } |