Add support for a variadic ioctl() function. The ioctl() interface is a non-standard, Unix interface. NuttX has always used the older, three-parameter version. Most contemporary systems now, however, use a variadic form of the ioctl() function. Added an option to insert a shim layer to adapt the three-parameter ioctl() to use the variadic interface form. Internally, the ioctl handling is the same three-parameter logic. The only real complexity to the shim is in how the system calls must be handled.
This commit is contained in:
parent
19d31412f7
commit
e31d5125ae
42
TODO
42
TODO
@ -1,4 +1,4 @@
|
||||
NuttX TODO List (Last updated November 27, 2014)
|
||||
NuttX TODO List (Last updated November 29, 2014)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
@ -18,7 +18,7 @@ nuttx/
|
||||
(13) Network (net/, drivers/net)
|
||||
(4) USB (drivers/usbdev, drivers/usbhost)
|
||||
(10) Libraries (libc/, )
|
||||
(12) File system/Generic drivers (fs/, drivers/)
|
||||
(11) File system/Generic drivers (fs/, drivers/)
|
||||
(8) Graphics subystem (graphics/)
|
||||
(1) Pascal add-on (pcode/)
|
||||
(1) Documentation (Documentation/)
|
||||
@ -1172,44 +1172,6 @@ o File system / Generic drivers (fs/, drivers/)
|
||||
Status: Open
|
||||
Priority: Medium
|
||||
|
||||
Title: IOCTL() IS NO LONGER STANDARD
|
||||
Description: The function prototype for ioctl() is no longer standard. It
|
||||
was more-or-less standard at one time. The NuttX ioctl is the
|
||||
historic System 7 Unix, three-parameter version.
|
||||
|
||||
int ioctl(int fd, int req, unsigned long arg);
|
||||
|
||||
Current definitions now allow for the third parameter to be
|
||||
optional (and, I suppose, could accept additional arguments).
|
||||
For example, OpenGroup
|
||||
(http://pubs.opengroup.org/onlinepubs/009695399/functions/ioctl.html):
|
||||
|
||||
int ioctl(int fildes, int request, ... /* arg */);
|
||||
|
||||
Linux man page:
|
||||
|
||||
int ioctl(int d, unsigned long request, ...);
|
||||
|
||||
FreeBSD:
|
||||
|
||||
int ioctl(int fd, unsigned long request, ...);
|
||||
|
||||
I imagine that making the thread argument variadic, the logic
|
||||
is rescued for the case with modern 64-bit computers where
|
||||
sizeof(long) < sizeof(pointer).
|
||||
|
||||
Since NuttX relies on OpenGroup for interface definitions, the
|
||||
current NuttX definition is incompatible with the standard in
|
||||
any event.
|
||||
|
||||
Unfortunately, the change would be very extensive. If the
|
||||
type of the argument depends on the 'request', then the third
|
||||
argument would have to be decoded by every device device
|
||||
driver. That would be an enormous job and will not happen soon.
|
||||
Status: Open
|
||||
Priority: Very low until I run into a machine with sizeof(long) <
|
||||
sizeof(pointer)
|
||||
|
||||
o Graphics subsystem (graphics/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ioctl
|
||||
* Name: ioctl/fs_ioctl
|
||||
*
|
||||
* Description:
|
||||
* Perform device specific operations.
|
||||
@ -85,7 +85,11 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
int fs_ioctl(int fd, int req, unsigned long arg)
|
||||
#else
|
||||
int ioctl(int fd, int req, unsigned long arg)
|
||||
#endif
|
||||
{
|
||||
int err;
|
||||
#if CONFIG_NFILE_DESCRIPTORS > 0
|
||||
|
@ -624,6 +624,40 @@ int open_blockdriver(FAR const char *pathname, int mountflags,
|
||||
int close_blockdriver(FAR struct inode *inode);
|
||||
#endif
|
||||
|
||||
/* fs/vfs/fs_ioctl.c ********************************************************/
|
||||
/****************************************************************************
|
||||
* Name: fs_ioctl
|
||||
*
|
||||
* Description:
|
||||
* Perform device specific operations.
|
||||
*
|
||||
* Parameters:
|
||||
* fd File/socket descriptor of device
|
||||
* req The ioctl command
|
||||
* arg The argument of the ioctl cmd
|
||||
*
|
||||
* Return:
|
||||
* >=0 on success (positive non-zero values are cmd-specific)
|
||||
* -1 on failure withi errno set properly:
|
||||
*
|
||||
* EBADF
|
||||
* 'fd' is not a valid descriptor.
|
||||
* EFAULT
|
||||
* 'arg' references an inaccessible memory area.
|
||||
* EINVAL
|
||||
* 'cmd' or 'arg' is not valid.
|
||||
* ENOTTY
|
||||
* 'fd' is not associated with a character special device.
|
||||
* ENOTTY
|
||||
* The specified request does not apply to the kind of object that the
|
||||
* descriptor 'fd' references.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
int fs_ioctl(int fd, int req, unsigned long arg);
|
||||
#endif
|
||||
|
||||
/* fs_fdopen.c **************************************************************/
|
||||
/****************************************************************************
|
||||
* Name: fs_fdopen
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* include/sys/ioctl.h
|
||||
*
|
||||
* Copyright (C) 2007, 2008, 2012 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007, 2008, 2012, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -55,14 +55,6 @@
|
||||
* Pre-Processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
@ -72,9 +64,46 @@ extern "C"
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* ioctl() is a non-standard UNIX-like API */
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ioctl/fs_ioctl
|
||||
*
|
||||
* Description:
|
||||
* Perform device specific operations.
|
||||
*
|
||||
* ioctl() is a non-standard UNIX-like API
|
||||
*
|
||||
* Parameters:
|
||||
* fd File/socket descriptor of device
|
||||
* req The ioctl command
|
||||
* arg The argument of the ioctl cmd
|
||||
*
|
||||
* Return:
|
||||
* >=0 on success (positive non-zero values are cmd-specific)
|
||||
* -1 on failure withi errno set properly:
|
||||
*
|
||||
* EBADF
|
||||
* 'fd' is not a valid descriptor.
|
||||
* EFAULT
|
||||
* 'arg' references an inaccessible memory area.
|
||||
* EINVAL
|
||||
* 'cmd' or 'arg' is not valid.
|
||||
* ENOTTY
|
||||
* 'fd' is not associated with a character special device.
|
||||
* ENOTTY
|
||||
* The specified request does not apply to the kind of object that the
|
||||
* descriptor 'fd' references.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
int ioctl(int fd, int req, ...);
|
||||
#else
|
||||
int ioctl(int fd, int req, unsigned long arg);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
@ -229,7 +229,11 @@
|
||||
|
||||
#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
|
||||
# define SYS_close (__SYS_descriptors+0)
|
||||
# define SYS_ioctl (__SYS_descriptors+1)
|
||||
# ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
# define SYS_fs_ioctl (__SYS_descriptors+1)
|
||||
# else
|
||||
# define SYS_ioctl (__SYS_descriptors+1)
|
||||
# endif
|
||||
# define SYS_read (__SYS_descriptors+2)
|
||||
# define SYS_write (__SYS_descriptors+3)
|
||||
# define SYS_pread (__SYS_descriptors+4)
|
||||
|
26
libc/Kconfig
26
libc/Kconfig
@ -48,6 +48,32 @@ config LIBC_FLOATINGPOINT
|
||||
By default, floating point
|
||||
support in printf, sscanf, etc. is disabled.
|
||||
|
||||
config LIBC_IOCTL_VARIADIC
|
||||
bool "Enable variadic ioctl()"
|
||||
default n
|
||||
---help---
|
||||
By default, NuttX implements the "old style," three-parameter,
|
||||
ioctl() interface with this function prototype:
|
||||
|
||||
int ioctl(int fd, int req, unsigned long arg);
|
||||
|
||||
That function is implemented as part of the VFS. If
|
||||
LIBC_IOCTL_VARIADIC is selected, then an additional compatibility
|
||||
layer will be provided in the C library. The enabled, then function
|
||||
prototype will become:
|
||||
|
||||
int ioctl(int fd, int req, ...);
|
||||
|
||||
The ioctl() is not controlled by any standard so it is really
|
||||
arbitrary which format you used. You may select the variadic
|
||||
function prototype with this option. That will slightly increase
|
||||
code size and ioctl() processing time. It will not support a
|
||||
variable number of arguments and it still always expects to see a
|
||||
third argument of type 'unsigned long'. The only benefit of this
|
||||
alternative function signature is that it may provide greater
|
||||
compatibility if you are porting code from other platforms that use
|
||||
the variadic ioctl() function.
|
||||
|
||||
config LIB_RAND_ORDER
|
||||
int "Order of the random number generate"
|
||||
default 1
|
||||
|
@ -42,18 +42,28 @@ CSRCS += lib_stream.c lib_filesem.c
|
||||
ifneq ($(CONFIG_NFILE_DESCRIPTORS),0)
|
||||
|
||||
CSRCS += lib_sendfile.c
|
||||
|
||||
ifneq ($(CONFIG_NFILE_STREAMS),0)
|
||||
CSRCS += lib_streamsem.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LIBC_IOCTL_VARIADIC),y)
|
||||
CSRCS += lib_ioctl.c
|
||||
endif
|
||||
|
||||
else
|
||||
ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0)
|
||||
|
||||
CSRCS += lib_sendfile.c
|
||||
|
||||
ifneq ($(CONFIG_NFILE_STREAMS),0)
|
||||
CSRCS += lib_streamsem.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LIBC_IOCTL_VARIADIC),y)
|
||||
CSRCS += lib_ioctl.c
|
||||
endif
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
|
101
libc/misc/lib_ioctl.c
Normal file
101
libc/misc/lib_ioctl.c
Normal file
@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
* libc/misc/lib_ioctl.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
#include "lib_internal.h"
|
||||
|
||||
#if defined(CONFIG_LIBC_IOCTL_VARIADIC) && CONFIG_NFILE_DESCRIPTORS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ioctl/fs_ioctl
|
||||
*
|
||||
* Description:
|
||||
* Perform device specific operations.
|
||||
*
|
||||
* Parameters:
|
||||
* fd File/socket descriptor of device
|
||||
* req The ioctl command
|
||||
* ... One argument of type unsigned long is expected
|
||||
*
|
||||
* Return:
|
||||
* >=0 on success (positive non-zero values are cmd-specific)
|
||||
* -1 on failure withi errno set properly:
|
||||
*
|
||||
* EBADF
|
||||
* 'fd' is not a valid descriptor.
|
||||
* EFAULT
|
||||
* 'arg' references an inaccessible memory area.
|
||||
* EINVAL
|
||||
* 'cmd' or 'arg' is not valid.
|
||||
* ENOTTY
|
||||
* 'fd' is not associated with a character special device.
|
||||
* ENOTTY
|
||||
* The specified request does not apply to the kind of object that the
|
||||
* descriptor 'fd' references.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ioctl(int fd, int req, ...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned long arg;
|
||||
|
||||
/* Get the unsigned long argument */
|
||||
|
||||
va_start(ap, req);
|
||||
arg = va_arg(ap, unsigned long );
|
||||
va_end(ap);
|
||||
|
||||
/* Then let fs_ioctl() to the real work */
|
||||
|
||||
return fs_ioctl(fd, req, arg);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_LIBC_IOCTL_VARIADIC && CONFIG_NFILE_DESCRIPTORS > 0 */
|
@ -20,13 +20,14 @@
|
||||
"exit","stdlib.h","","void","int"
|
||||
"fcntl","fcntl.h","CONFIG_NFILE_DESCRIPTORS > 0","int","int","int","..."
|
||||
"fs_fdopen","nuttx/fs/fs.h","CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0","FAR struct file_struct*","int","int","FAR struct tcb_s*"
|
||||
"fs_ioctl","nuttx/fs/fs.h","defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long"
|
||||
"fsync","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","int"
|
||||
"get_errno","errno.h","","int"
|
||||
"getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*"
|
||||
"getpid","unistd.h","","pid_t"
|
||||
"getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*"
|
||||
"gettimeofday","sys/time.h","","int","struct timeval*","FAR void*"
|
||||
"ioctl","sys/ioctl.h","CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0","int","int","int","unsigned long"
|
||||
"ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long"
|
||||
"kill","signal.h","!defined(CONFIG_DISABLE_SIGNALS)","int","pid_t","int"
|
||||
"listen","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int"
|
||||
"lseek","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0","off_t","int","off_t","int"
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -160,7 +160,11 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert)
|
||||
|
||||
#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
|
||||
SYSCALL_LOOKUP(close, 1, STUB_close)
|
||||
# ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
SYSCALL_LOOKUP(fs_ioctl, 3, STUB_fs_ioctl)
|
||||
# else
|
||||
SYSCALL_LOOKUP(ioctl, 3, STUB_ioctl)
|
||||
# endif
|
||||
SYSCALL_LOOKUP(read, 3, STUB_read)
|
||||
SYSCALL_LOOKUP(write, 3, STUB_write)
|
||||
SYSCALL_LOOKUP(pread, 4, STUB_pread)
|
||||
|
@ -161,8 +161,13 @@ uintptr_t STUB_timer_settime(int nbr, uintptr_t parm1, uintptr_t parm2,
|
||||
*/
|
||||
|
||||
uintptr_t STUB_close(int nbr, uintptr_t parm1);
|
||||
#ifdef CONFIG_LIBC_IOCTL_VARIADIC
|
||||
uintptr_t STUB_fs_ioctl(int nbr, uintptr_t parm1, uintptr_t parm2,
|
||||
uintptr_t parm3);
|
||||
#else
|
||||
uintptr_t STUB_ioctl(int nbr, uintptr_t parm1, uintptr_t parm2,
|
||||
uintptr_t parm3);
|
||||
#endif
|
||||
uintptr_t STUB_read(int nbr, uintptr_t parm1, uintptr_t parm2,
|
||||
uintptr_t parm3);
|
||||
uintptr_t STUB_write(int nbr, uintptr_t parm1, uintptr_t parm2,
|
||||
|
Loading…
Reference in New Issue
Block a user