From 7065a89fc6b5f301505d8912251aa60bda67046e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 27 Oct 2020 20:22:55 +0100 Subject: [PATCH] POSIX: ioctl(fd, op, arg) equals ioctl(fd, op, arg, 0) The ioctl call cannot know the expected number of arguments because it depends on the specific ioctl being used, and the same value could be used to do different things by different devices. Without knowing that, it is not safe to use va_arg (at best a random value will be read from the stack, at worst, it will just crash). This changes the implementation of ioctl in two ways: - For C++ code: a 4 argument function with default values for arguments 3 and 4. - For C code: wrap arguments 3 and 4 in a struct with the help of a macro, providing something that behaves like the C++ version. So, with this new code: - Calling ioctl with only 3 arguments sets the 4th one to 0 - Calling ioctl with only 2 arguments sets the 3rd and 4th to 0 - Calling with 1 or 5+ arguments is a compile time error The existing ioctl symbol is preserved for ABI compatibility. Change-Id: I6d4d1d38fccd8cc9bd94203d3e11aeac6da8efc3 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3360 Reviewed-by: Adrien Destugues --- headers/posix/unistd.h | 16 ++++++++++++++++ src/system/libroot/posix/unistd/ioctl.c | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index 94fa05d71a..54fb22a30e 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -190,7 +190,23 @@ extern int symlinkat(const char *toPath, int fd, const char *symlinkPath); extern int ftruncate(int fd, off_t newSize); extern int truncate(const char *path, off_t newSize); +struct ioctl_args { + void* argument; + size_t size; +}; +int __ioctl(int fd, ulong cmd, struct ioctl_args args); +#ifndef __cplusplus extern int ioctl(int fd, unsigned long op, ...); +#ifndef _KERNEL_MODE +#define ioctl(a, b, c...) __ioctl(a, b, (struct ioctl_args){ c }) +#endif +#else +inline int +ioctl(int fd, unsigned long op, void* argument = NULL, size_t size = 0) +{ + return __ioctl(fd, op, (struct ioctl_args){ argument, size }); +} +#endif extern ssize_t read(int fd, void *buffer, size_t count); extern ssize_t read_pos(int fd, off_t pos, void *buffer, size_t count); diff --git a/src/system/libroot/posix/unistd/ioctl.c b/src/system/libroot/posix/unistd/ioctl.c index 3f733df137..7182e5bfbe 100644 --- a/src/system/libroot/posix/unistd/ioctl.c +++ b/src/system/libroot/posix/unistd/ioctl.c @@ -13,6 +13,14 @@ #include +int +__ioctl(int fd, ulong cmd, struct ioctl_args args) +{ + RETURN_AND_SET_ERRNO(_kern_ioctl(fd, cmd, args.argument, args.size)); +} + + +#undef ioctl int ioctl(int fd, ulong cmd, ...) {