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:
Gregory Nutt 2014-11-29 10:53:22 -06:00
parent 19d31412f7
commit e31d5125ae
11 changed files with 233 additions and 53 deletions

42
TODO
View File

@ -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/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
View 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 */

View File

@ -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.

View File

@ -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)

View File

@ -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,