Files
m241Neelima/vxworks-6.9/target/src/os/io/ioLib.c
T

2116 lines
68 KiB
C

/* ioLib.c - I/O interface library */
/*
* Copyright (c) 1984-2016 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
10mar16,dlk Fix failure to open some cross-device symbolic link paths
dependent on current working directory (VXW6-85211).
Fix handling of more than 2 initial '/' characters by
ioFullFileNameGet() in POSIX PSE52 mode (VXW6-85415).
08z,08dec15,h_k fixed dead lock between mmanFdMap() and ioCreateOrOpen()
introduced by fix for VXW6-84729. (VXW6-85129)
08y,20jul15,h_k corrected saved device name and missing io lock release in
ioCreateOrOpen(). (VXW6-84706)
08x,24apr15,h_k added pDevHdr protection between open and remove.
(VXW6-84279)
08w,04nov14,wap VXW6-8649 - Update documentation for open() to better
describe the path lookup behavior used when accessing
filesystems.
08v,30sep14,jpb VXW6-82899. ioTaskStdGet should return ERROR if called from
ISR.
08u,17sep14,jpb VXW6-82689: Updated ioctl errno.
08t,13aug13,krz Fixed potential null dereference.
08s,23feb12,txu Fix WIND00294182: the file offset is changed to zero when
lseek SEEK_END fail, which does not conform with POSIX specs.
08r,22apr11,jxu Added support for kernel per-task CWD feature (WIND00131452),
and fixed potential memory leak introduced by 08p.
08q,17nov10,sjz Fix WIND00215931: remove race condition when using removable
devices such as a USB stick.
08p,11nov10,myt Fix WIND00237838:check if dev is actually deleted or replaced.
08o,28oct10,zly Fix WIND00235254:corret the doc of write().
08n,19oct10,jxu Fix defect WIND00229665: big endian issue when calls FIONREAD.
08m,11nov10,zly Fix WIND00188899:added check for buffer parameter in
ioReadWrite().
08l,25sep10,jxu Removed type cast FUNCPTR for _func_consoleOut.
08k,26aug10,jxu Fixed defects WIND00227889 WIND00226143 WIND00229816: remove
usage of pathCondense() in function ioFullFileNameGet().
07j,04aug10,zly Fix WIND00224783: care of device delete during open, judge if
dev has been deleted in the ioCreateOrOpen().
07i,08jul10,jxu modified lseek to support seek position larger than UINT_MAX
on vxWorks 64-bit.
07h,27may10,sjz fix WIND00210965: resolve ".." and "." in the path.
07g,15apr10,jpb Added pthreadLibP.h for _func_pthread_testandset_canceltype.
07f,25jan09,lxj adapt function readv writev to LP64 and change the third
argument type from _Vx_usr_arg_t to _Vx_ioctl_arg_t
07e,20jul09,zly Remove warning.
07d,22apr09,hps LP64: no need drv_val_t any more
07c,21apr09,hps LP64: move drv_val_t to private header iosLibP.h
07b,20apr09,jpb Added include of memPartLibP.h after removing the inclusion
of memPartLib.h from poolLib.h.
07a,20mar09,hps LP64 support
06z,27aug08,jpb Renamed VSB header file
06y,13aug08,zly set printf function pointer in ioTaskStdSet,
as same as ioGlobalStdSet`s logic.(WIND00129707).
06x,19jun08,jpb Added include path for kernel configurations options set in
vsb.
06w,12may08,jpb Modifications for source build. Renamed
WV_INSTRUMENTATION to _WRS_CONFIG_SV_INSTRUMENTATION.
06v,11sep07,act move lseek back to ioLib (basic I/O) for now - stdio needs it
06u,31aug07,act set printf function pointer in ioGlobalStdSet, not iosInit
06t,18jan07,pcm moved file system routines to fsIoLib.c
06s,29mar07,act WIND00060945: ioctl() should be variable-argument function
06r,09nov06,pcm modified creat() comments for <mode> for NFS (WIND00067060)
06q,24aug06,jpb Fixed warnings for coverity
06p,21aug06,jpb Removed _func_rtpPthreadSetCancelType references
(WIND00062557)
06o,07apr06,dgp doc: fix formatting in SEE ALSO, library
06q,12jun06,pcm made modifications for pthread cancellation points
06p,03apr06,act when opening with O_CNTRL fails we have to unmap specially
06o,30mar06,jlk SPR 119715. Fixed declaration of getcwd()
06n,28feb06,pcm fixed SPR 118088 (typo in parameter <mode> description)
06m,13feb06,pcm updated creat() documentation
06l,02mar06,act fix errno for F_DUPFD and F_SETFD invalid arguments
06k,14feb06,dcc fixed calculation of file size in lseek (...SEEK_END).
06j,14feb06,md in pse52 mode reserve slots in the fd table for control mode
06i,09feb06,jlk Now uses iosPse52Mode instead of posixPse52Mode and
fixed fcntl to set errno when F_DUPFD ran out of file
descriptors
06h,07feb06,jlk Fixed RTP dependency introduced in 06e
06g,06feb06,act fix FOLLOW_LINK handling
06f,03feb06,jlk "/" munching for POSIX
06e,01feb06,md fix opening files that have O_CNTRL set
06d,06jan06,act add POSIX file locking
06c,04jan06,rfr Fixed path handling for "/" device
06b,20sep05,hya changed chdir to support relative path.
06a,25aug05,hya removed stack var fullFileName[MAX_FILENAME_LENGTH].
05z,12aug05,hya made iosDevSuspend() related changes.
05y,13jun05,tcr add System Viewer instrumentation
05x,17may05,hya added trailing / fix in device name
05w,15apr05,hya replaced iosClose with iosCloseInLine.
05v,24mar05,hya update manual of open, read, write, ioctl.
05u,02mar05,hya change for user memory validation in ioctl
05t,10jan05,hya moved pathCondense up in ioDefPathCat.
05s,31dec04,hya made ioDefPath check in remove().
05r,25jan05,dgp update Guide refs and config info, migrate to apigen markup
05q,02nov04,hya updated open() man page.
05p,01oct04,yvp Changed lseek prototype to use off_t (for Posix).
05o,23sep04,yvp Fix SPR 99907: ioStdFd's initialized to invalid values (-1).
05n,10aug04,kk renamed rtpIdKernel to kernelId
05n,30aug04,yvp Changed rtpIoXXX calls to iosRtpXXX.
05n,07sep04,jyo Fixing SPR 100119: Removing references to RT11.
05m,06jul04,jyo Change the mention of O_SYNC support availability only for
DOS volumes.
05l,01jul04,jyo Documenting the support of O_SYNC in open() and creat().
05k,10jun04,pad Added user-side pthread cancellation points.
05j,28apr04,dat remove iosCloseInLine, 96826, chg'd ioGlobalStdSet and
ioTaskStdSet to verify the newFd and to return STATUS (97227)
05i,07apr04,dat cd to fail if path is not valid (30567)
05h,27feb04,dat merging iosLib and rtpIoLib, update open documentation
SPR 94538. new error handling for open/create
05g,19feb04,dat Consolidate kernel IO with rtp IO, SPR 92613
05f,03feb04,dat mangen errors/warnings
05e,08dec03,dat adding const to chdir and unlink args
05d,05dec03,dat fix for CreateOrOpen error handling
05c,10nov03,dat refactoring for RTP support
05b,29oct03,dat lint removal, new FD_ENTRY fields.
05a,28jul03,dat removing warnings, stricter const char * attributes
04z,31jan03,pmr SPR 82273: fixed linkCount declaration in ioCreateOrOpen().
---,-------,--- SPR 80447: fixed remove() to follow symbolic links.
04y,13jan03,gls moved check for NULL name in ioCreateOrOpen() (SPR #82909)
04x,02Aug00,jgn merge DOT-4 pthreads code +
---,-------,--- add validation of null pointer for name as well as null string
04w,03oct01,dcb Fix SPR 20033 side effect --- handle new return code from
---,-------,--- iosFdSet. Combine open() and creat() into one function.
04v,01mar99,yp SPR 21655 - if iosDevFind() fails open() dosn't free fd
04u,21feb99,jdi doc: listed errnos.
04t,03sep97,dgp doc: SPR 9023 - correct reference to FIOGETNAME in ioctl()
04s,10jul97,dgp doc: fix SPR 6117, rename() not supported on all devices
04r,20oct95,jdi doc: addition for rename() (SPR 4167); added bit values
for open() and creat() flags (SPR 4276).
04q,10feb95,rhp added names of stdio fd macros to ioLib man page
04p,26jul94,dvs added doc for read/write if no driver routine (SPR #2019/2020).
04o,30sep93,jmm resubmitted change originally in scd 10148
04n,08feb93,smb changed int to size_t for read and write.
04m,21jan93,jdi documentation cleanup for 5.1.
04l,29jul92,smb added isatty for use by stdio library.
04k,22jul92,kdl Replaced delete() with remove().
04j,18jul92,smb Changed errno.h to errnoLib.h.
04i,04jul92,jcf scalable/ANSI/cleanup effort.
04h,26may92,rrr the tree shuffle
04g,28feb92,wmd added bzero() call in ioFullFileNameGet() to init to 0's
fullPathName[] buffer before it is passed to subordinates.
04f,05dec91,rrr made lseek take posix arguments (SEEK_)
04e,25nov91,llk ansi stuff. Modified remove() and rename().
included stdio.h.
04d,25nov91,rrr cleanup of some ansi warings.
04c,04oct91,rrr passed through the ansification filter
-changed functions to ansi style
-changed includes to have absolute path from h/
-changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
-changed VOID to void
-changed copyright notice
04b,05apr91,jdi documentation -- removed header parens and x-ref numbers;
doc review by dnw.
04a,08feb91,jaa documentation cleanup.
03z,15oct90,dnw made ioFullFileNameGet() be NOMANUAL
03y,05oct90,dnw made readv, writev, ioDefDevGet, ioDefDirGet be NOMANUAL
made ioFullFileNameGet() use pathCat()
added chdir(), getcwd(), rename() for POSIX compliance
added remove() for ANSI compliance
added ioDefPathCat() (NOMANUAL)
03x,06jun90,rdc added readv and writev.
03w,25may90,dnw changed creat and open to NOT malloc filename before calling
iosFdSet. This is now left up to iosFdSet.
03v,11may90,yao added missing modification history (03u) for the last checkin.
03u,09may90,yao typecasted malloc to (char *).
03t,01may90,llk changed call to pathCat(). Now, pathCat() checks if a name
is too long, and returns ERROR if it is.
03s,14apr90,jcf removed tcb extension dependencies.
03r,01apr90,llk changed ioFullFileNameGet() and ioDefPathSet() so that only
filenames of MAX_FILENAME_LENGTH characters or less will
be accepted.
03q,14mar90,jdi documentation cleanup.
03p,12dec89,dab documentation.
03o,15nov89,dab changed variable name mode to flag in creat(). documentation.
rdc added unlink, getwd for unix compatibility.
03n,02may89,dab documentation touchup in lseek().
03m,23mar89,dab made L_XTND option work in lseek(); fixed L_INCR bug in
lseek(); documentation touchup in creat().
03l,23nov88,llk fixed bug in handling multiple links.
dnw changed ioTaskStd{Set,Get} to take taskId arg.
03k,08oct88,gae made global standard fd array local.
03j,07sep88,gae documentation.
03i,29aug88,gae documentation.
03h,15aug88,jcf lint.
03g,15jul88,llk changed to allocate an fd name before calling iosFdSet or
iosFdNew.
03f,30jun88,llk changed open and create so that they handle links.
03e,04jun88,llk uses a default path instead of a default device.
changed ioDefDev to ioDefPath.
added ioDefPathPrompt, ioDefPathShow, ioDefPathSet,
ioDefPathGet, ioDefDirGet.
rewrote ioDefDevGet.
removed ioSetDefDev.
added ioFullFileNameGet.
03d,30may88,dnw changed to v4 names.
03c,28may88,dnw deleted obsolete create().
03b,27may88,llk see change 03e above.
03a,30mar88,gae made I/O system, i.e. iosLib, responsible for low-level
creat,open,read,write,close calls to drivers as
fdTable & drvTable are now hidden.
added parameters to open() for UNIX compatibility.
made L_INCR option work in lseek().
added io{G,S}et{Global,Task}Std().
02u,19apr88,llk added a parameter to open. Inspired by NFS and aspirations
toward UNIX compatibility.
02t,31dec87,jlf made creat and open follow links.
02s,05nov87,jlf documentation
02r,30sep87,gae removed usage of fdTable by using new iosFdSet().
added FIOGETNAME to ioctl.
02q,28aug87,dnw changed creat() and open() to only treat ERROR (-1) as error
indication from driver routines instead of < 0 to allow
driver values (i.e. structure pointers) to be in memory
with high bit set.
02p,28apr87,gae close() now returns status; added UNIX compatible creat().
02o,24mar87,jlf documentation
02n,25feb87,ecs minor documentation.
added include of strLib.h.
02m,14feb87,dnw changed create(), open(), delete() to return ERROR if null
filename is specified. However, filename "." is turned
into null filename before being passed to driver routine.
02l,20dec86,dnw fixed ioGetDefDevTail() to require complete match of dev name.
changed to not get include files from default directories.
02k,07oct86,gae added ioGetDefDevTail().
02j,04sep86,jlf minor documentation
02i,01jul86,jlf minor documentation
02h,03apr86,llk fixed syntax error in lseek.
02g,03mar86,jlf changed ioctrl calls to ioctl.
added lseek.
xxx, deleted pre 86 history - see RCS
*/
/*
DESCRIPTION
This library contains the interface to the basic I/O system.
It includes:
\ms
\m -
Interfaces to the seven basic driver-provided functions:
creat(), remove(), open(), close(), read(), write(), and ioctl().
\m -
Interfaces to several file system functions, including
rename() and lseek().
\m -
Routines to set and get the current working directory.
\m -
Routines to assign task and global standard file descriptors.
\me
FILE DESCRIPTORS
At the basic I/O level, files are referred to by a file descriptor.
A file descriptor is a small integer returned by a call to open() or creat().
The other basic I/O calls take a file descriptor as a parameter to specify
the intended file.
Three file descriptors are reserved and have special meanings:
\cs
0 (`STD_IN') - standard input
1 (`STD_OUT') - standard output
2 (`STD_ERR') - standard error output
\ce
VxWorks allows two levels of redirection. First, there is a global
assignment of the three standard file descriptors. By default, new tasks use
this global assignment. The global assignment of the three standard
file descriptors is controlled by the routines ioGlobalStdSet() and
ioGlobalStdGet().
Second, individual tasks may override the global assignment of these
file descriptors with their own assignments that apply only to that task.
The assignment of task-specific standard file descriptors is controlled
by the routines ioTaskStdSet() and ioTaskStdGet().
CONFIGURATION:
To include the I/O interface library, configure VxWorks with the
INCLUDE_IO_SYSTEM component.
INCLUDE FILES: ioLib.h, stdio.h
SEE ALSO:
iosLib, 'ansiStdio',
the VxWorks programmer guides.
*/
/* LINTLIBRARY */
#include <vxWorks.h>
#include <vsbConfig.h>
#include <sys/types.h>
#include <memLib.h>
#include <ioLib.h>
#include <sys/stat.h>
#include <taskLib.h>
#include <net/uio.h>
#include <errnoLib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pathLib.h>
#include <string.h>
#define __PTHREAD_SRC
#include <pthread.h>
#include <private/pthreadLibP.h> /* _func_pthread_testandset_canceltype */
#include <private/rtpLibP.h> /* for RTP internals */
#include <private/rtpIoLibP.h>
#include <private/iosLibP.h>
#include <private/memPartLibP.h>
#include <private/intLibP.h>
/* define */
#define STD_VALID(fd) (((fd) >= 0) && ((fd) < 3))
/* extern variable declaration */
/*
* uncomment the line below to measure open, close, read
* and write system calls for 'enc' command.
*/
/* #define MEASURE_SYS_CALLS */
#ifdef MEASURE_SYS_CALLS
extern int measurementFlag;
extern TASK_ID sysCallTaskID;
extern UINT32 tsFreq;
enum kernelAPI
{
openCall=0,
closeCall,
readCall,
writeCall,
sysCallMax,
};
typedef struct
{
unsigned int sysCallCount;
unsigned long int execTimeUsec;
}KRNL_API_STATS;
KRNL_API_STATS API_STATS[sysCallMax];
#endif
/* this tells core I/O if the system is configured for PSE52 */
extern BOOL iosPse52Mode;
extern DRV_ENTRY fdInvalidDrv;
/* local function declaration */
LOCAL int ioCreateOrOpen (const char * name, int flags, int mode, BOOL create);
LOCAL STATUS openDrvRefCntInc (DEV_HDR * pDevHdr);
LOCAL void openDrvRefCntDec (DEV_HDR * pDevHdr);
/* local variable */
/*
* Ensure global stdin/stdout/stderr are ERROR until set to real values.
* This may be used in target/src/arch/<arch>/excArchLib.c to improve
* diagnosis of exceptions which occur before I/O is set up.
*/
LOCAL int ioStdFd[3] = { ERROR, ERROR, ERROR };
/* global variable */
int ioMaxLinkLevels = 20; /* maximum number of symlinks to traverse */
STATUS (*_func_ioPxCreateOrOpen) (BOOL, int *, int, int *) = NULL;
int (*_func_fcntl_dup) (int, int) = NULL;
STATUS (*_func_iosOpenDrvRefCntInc) (DEV_HDR * pDevHdr);
void (*_func_iosOpenDrvRefCntDec) (DEV_HDR * pDevHdr);
/*******************************************************************************
*
* creat - create a file
*
* This routine creates a file called <name> and opens it with a specified
* <flag>. This routine determines on which device to create the file;
* it then calls the create routine of the device driver to do most of the work.
* Therefore, much of what transpires is device/driver-dependent.
*
* The parameter <flag> is set to O_RDONLY (0), O_WRONLY (1), O_RDWR (2)
* for the duration of time the file is open.
*
* The parameter <flag> can be set to O_SYNC, on dosFs volumes, indicating that
* each write should be immediately written to the backing media. This flag
* synchronizes the FAT and the directory entries.
*
* On NFS and POSIX compliant file systems such as HRFS, the parameter <flag>
* refers instead to the UNIX style file permission bits.
*
* \INTERNAL
* A driver's create routine will return FOLLOW_LINK if any part of the file name
* contains a link (in the directory path). In this case, it will also
* have changed the name of the file being opened to incorporate the name of
* the link. The new file name is then repeatedly resubmitted to the driver's
* open routine until all links are resolved.
*
* NOTE
* For more information about situations when there are no file descriptors
* available, see the reference entry for iosInit().
*
* RETURNS
* A file descriptor number, or ERROR if a filename is not specified, the
* device does not exist, no file descriptors are available, or the driver
* returns ERROR.
*
* ERRNO
* \is
* \i ELOOP
* Circular symbolic link, too many links.
* \i EMFILE
* Maximum number of files already open.
* \i S_iosLib_DEVICE_NOT_FOUND (ENODEV)
* No valid device name found in path.
* \i others
* Other errors reported by device drivers.
* \ie
*
* SEE ALSO: open()
*/
int creat
(
const char *name, /* name of the file to create */
int flag /* file permissions */
)
{
return (ioCreateOrOpen (name, flag, 0, TRUE));
}
/*******************************************************************************
*
* open - open a file
*
* This routine opens a file for reading, writing, or updating, and returns
* a file descriptor for that file. The arguments to open() are the filename
* <name> and the type of access set in <flags> and a UNIX chmod-style file mode
* <mode>.
*
* The parameter <flags> is set to one or a combination of the following access
* settings by bitwise OR operation for the duration of time the file is open.
* The following list is just a generic description of supported settings. Their
* availability and effect with or without combination among them change
* from device to device. Check the specific device manual for further details.
*
* \is
* \i O_RDONLY
* Open for reading only.
* \i O_WRONLY
* Open for writing only.
* \i O_RDWR
* Open for reading and writing.
* \i O_CREAT
* Create a file if not existing.
* \i O_EXCL
* Error on open if file exists and O_CREAT is also set.
* \i O_SYNC
* Write on the file descriptor complete as defined by synchronized I/O file
* integrity completion.
* \i O_DSYNC
* Write on the file descriptor complete as defined by synchronized I/O data
* integrity completion.
* \i O_RSYNC
* Read on the file descriptor complete at the same sync level as O_DSYNC and
* O_SYNC flags.
* \i O_APPEND
* If set, the file offset is set to the end of the file prior to each write.
* So writes are guaranteed at the end. It has no effect on devices other than
* the regular file system.
* \i O_NONBLOCK
* Non-blocking I/O if being set.
* \i O_NOCTTY
* Do not assign a ctty on this open, which does not cause the terminal device
* to become the controlling terminal for the process. Effective only on a
* terminal device.
* \i O_TRUNC
* Open with truncation. If the file exists and is a regular file, and the file
* is successfully opened, its length is truncated to 0. It has no effect on
* devices other than the regular file system.
* \ie
*
* In general, open() can only open pre-existing devices and files. However,
* files can also be created with open() by setting O_CREAT and perhaps some
* other like O_RDWR which depends on the file system implementation.
* In this case, the file is created with a UNIX chmod-style file mode, as
* indicated with the parameter <mode>. For example:
* \cs
* fd = open ("/usr/myFile", O_CREAT | O_RDWR, 0644);
* \ce
*
* Files, on dosFs volumes, can be opened with the O_SYNC flag indicating that
* each write should be immediately written to the backing media. This
* synchronizes the FAT and the directory entries.
*
* Note that, as in UNIX, the following are true: 1) filesystems are
* mounted on their own mount points, and 2) there is a default search
* path for tasks. These two points must be considered carefully when trying
* to access files on attached storage devices.
*
* Ultimately, the choice of which filesystem device to use when open()ing a
* file is controlled by iosDevFind(). Each filesystem has an I/O device
* header which contains the mount point name of the filesystem. When given
* a file name to open, iosDevFind() will iterate over each device header
* that's registered with the I/O subsystem looking for a mount point name
* that matches the file path (for example, if the file path name is
* /ata0:0/test.txt, this will match the device header entry with a mount
* point of /ata0:0). If no explicit match is found, iosDevFind() falls
* back to using the default or current working directory path, as specified
* using ioDevPathSet() (or chdir()).
*
* This logic seems straightforward enough, but there can be some subtle
* complications depending on the system configuration.
*
* Say that a system has an attached ATA disk drive, a USB thumb drive
* and a network interface. The ATA disk is mounted as /ata0:0, the thumb
* drive is mounted as /bd0, and the network filesystem (via the netDrv
* library) as host:. Given this, what happens if you attempt to perform
* an open("foo", O_RDONLY, 0) without specifying an absolute path?
*
* It turns out that the answer is that iosLib will attempt to open host:foo,
* meaning it will look for the file on the netDrv device. This is because the
* configlette for the INCLUDE_NETDRV component does an ioDefPathSet() to set
* the default iosLib path to "host:" (or whatever the specified remove server
* hostname is). When doing the open(), iosLib will attempt to match the path
* "foo" against the mount point paths /ata0:0, /bd0 and host:, but none of them
* will match explicitly, so it will fall back to trying the default path, which
* is the network filesystem. If there is no file "foo" on the network drive,
* then open() will fail, however the time it takes for it to return will depend
* on the network speed. Also, if the network link is down (say the cable is
* unplugged), the connect() timeout will have to elapse before open() returns,
* which typically takes about 75 seconds.
*
* Now let's say an attempt is made to perform an open("/bd0/foo", O_RDONLY, 0)
* instead. The iosLib code will again search through its list of device mount
* point names. If there is a mount point /bd0 present, then iosDevFind() will
* select that device, and an attempt will be made to open the file "foo" on
* the thumb drive.
*
* Note however that this only works if the USB thumb drive is plugged in
* at the time open() is called. If it's not, then the /bd0 filesystem won't
* be available yet, and iosDevFind() will again fall back to the default
* path, which in this case is the netDrv filesystem. This is something which
* can easily occur if an attempt is made to open() a file too early during
* system startup. USB storage devices in particular are not mounted
* immediately: even if the drive is plugged in at the time the system is
* booted, it takes some time for the USB stack to enumerate the bus, detect
* that a device is present and to attach it to the I/O subsystem.
*
* Therefore, if open() is called before the thumb drive has been mounted, even
* using an absolute pathname that reference the USB drive's mount point, the I/O
* subsystem will fail over to using the network drive path and time out. This
* is especially likely if the open() is done from usrAppInit(), since that
* function runs in tRootTask at a very high priority.
*
* The following caveat therefore applies:
*
* - Consider using ioDefPathSet() or chdir() to explicitly set the default
* working directory to the desired mount point path before calling open().
* Both functions will validate the specified path and return error if
* it's not currently mounted. For example, doing chdir("/bd0") will only
* succeed if /bd0 has in fact been mounted. This has the effect of
* overriding the default path set by the netDrv configlette and checking
* that desired device is mounted in the same step. If the device hasn't
* been mounted, it may be desirable to perform a delay and then call
* chdir() again until it succeeds before proceeding with the open().
*
*
* INTERNAL
* A driver's open routine will return FOLLOW_LINK if any part of the file name
* contains a link (directory path or file name). In this case, it will also
* have changed the name of the file being opened to incorporate the name of
* the link. The new file name is then repeatedly resubmitted to the driver's
* open routine until all links are resolved.
*
* NOTE
* For more information about situations when there are no file descriptors
* available, see the reference entry for iosInit().
*
* Also note that not all device drivers honor the flags or mode values when
* opening a file. Most simple devices simply ignore them and return an open
* file descriptor for both reading and writing. Read the device driver
* manual for information on this.
*
* RETURNS
* A file descriptor number, or ERROR if a file name is not specified, the
* device does not exist, no file descriptors are available, or the driver
* returns ERROR.
*
* ERRNO
* \is
* \i ELOOP
* Circular symbolic link, too many links.
* \i EMFILE
* Maximum number of files already open.
* \i S_iosLib_DEVICE_NOT_FOUND (ENODEV)
* No valid device name found in path.
* \i others
* Other errors reported by device drivers.
* \ie
*
* SEE ALSO: creat()
*/
int open
(
const char *name, /* name of the file to open */
int flags, /* access control flag */
int mode /* mode of file to create (UNIX chmod style) */
)
{
#ifdef MEASURE_SYS_CALLS
sysTimestampEnable();
UINT32 startTick = 0, endTick = 0, diffTick = 0;
UINT64 timeUs = 0;
UINT32 freq = tsFreq;
char toMeasure = (measurementFlag && (sysCallTaskID == taskIdSelf()));
if (toMeasure)
{
startTick = sysTimestamp();
(API_STATS[openCall].sysCallCount)++;
}
#endif
int result = ioCreateOrOpen(name, flags, mode, FALSE);
#ifdef MEASURE_SYS_CALLS
if (toMeasure)
{
endTick = sysTimestamp();
diffTick = endTick - startTick;
timeUs = ((UINT64)diffTick * 1000000ULL) / freq;
(API_STATS[openCall].execTimeUsec)+=timeUs;
}
#endif
return result;
}
/*******************************************************************************
*
* ioCreateOrOpen - creat() or open() a file
*
* This is the worker function for creat() and for open(). See their
* descriptions.
*
* RETURNS: New file descriptor or ERROR if the file could not be openend.
*
* ERRNO
* \is
* \i ELOOP
* Circular symbolic link, too many links.
* \i EMFILE
* Maximum number of files already open.
* \i S_iosLib_DEVICE_NOT_FOUND (ENODEV)
* No valid device name found in path.
* \i others
* Other errors reported by device drivers.
* \ie
*
* \NOMANUAL
*/
LOCAL int ioCreateOrOpen
(
const char *name, /* name of the file to create */
int flags, /* O_RDONLY, O_WRONLY, O_RDWR or O_CREAT (open call) */
int mode, /* mode of file to create (if open call) */
BOOL create /* set to TRUE if this is a creat() call */
)
{
DEV_HDR * pDevHdr1;
DEV_HDR * pDevHdr2;
DEV_HDR * pDevHdr3;
FD_ENTRY * pFdEntry;
void * value;
int fd;
char * fullFileName;
char * savedDevName;
const char *pPartFileName;
int linkCount = 1;
int unmapFlag = 0;
int krnPthreadCnclType; /* temp kernel canceltype saved value */
const char *pTail;
char * pOldDevName;
size_t nameLen;
RTP_ID curRtpId;
#ifdef _WRS_CONFIG_RTP
BOOL rtpIsLocked = FALSE;
#endif /* _WRS_CONFIG_RTP */
/*
* don't allow null filename (for user protection) but change
* "." into what null filename would be if we allowed it
*/
if ((name == NULL) || (name[0] == EOS))
{
errnoSet (S_ioLib_NO_FILENAME); /* ENODEV */
return (ERROR);
}
curRtpId = CUR_RTP_ID;
if ((fd = iosRtpFdReserve (curRtpId)) == ERROR)
{
if (_func_ioPxCreateOrOpen == NULL)
return (ERROR); /* Unable to get a free fd */
if (_func_ioPxCreateOrOpen (create, &unmapFlag, flags, &fd) != OK)
return (ERROR);
}
if ((pFdEntry = iosFdEntryGet ()) == NULL)
{
iosRtpFdUnmap2 (curRtpId, fd, unmapFlag);
return (ERROR); /* ENFILE */
}
if (strcmp (name, ".") == 0)
{
/* point to EOS (turn it into null filename) */
++name;
}
if ((fullFileName = KMEM_ALLOC (3 * MAX_FILENAME_LENGTH)) == NULL)
{
iosRtpFdUnmap2 (curRtpId, fd, unmapFlag);
iosFdEntryReturn (pFdEntry);
return (ERROR);
}
savedDevName = fullFileName + MAX_FILENAME_LENGTH;
pOldDevName = savedDevName + MAX_FILENAME_LENGTH;
/* from this point on, exit through handleError */
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (PTHREAD_CANCEL_ASYNCHRONOUS,
&krnPthreadCnclType);
/* lock I/O to prevent from changing the contetnt of the dev header */
(void) iosLock();
if ((ioFullFileNameGet (name, &pDevHdr1, fullFileName) == ERROR) ||
(pDevHdr1->name == NULL))
{
goto handleErrorWithUnlock;
}
/* record old DEV_HDR info */
strncpy (pOldDevName, pDevHdr1->name, MAX_FILENAME_LENGTH);
pOldDevName[MAX_FILENAME_LENGTH - 1] = EOS;
strncpy (savedDevName, pDevHdr1->name, MAX_FILENAME_LENGTH);
savedDevName[MAX_FILENAME_LENGTH - 1] = EOS;
/* increment drvRefCount to prevent from deletion */
if (openDrvRefCntInc (pDevHdr1) != OK)
{
goto handleErrorWithUnlock;
}
(void) iosUnlock();
for (;;)
{
if (create == TRUE)
value = iosCreate (pDevHdr1, fullFileName, flags);
else
value = iosOpen (pDevHdr1, fullFileName, flags, mode);
if (value == DRV_VAL_ERROR)
{
goto handleErrorWithDecRefCnt;
}
if (value != (void *)FOLLOW_LINK)
break;
/*
* if a file name contains a link, the driver's create routine changed
* fullFileName to incorporate the link's name. Keep processing using
* the new name. Save the new driver too, if there is a new driver.
*/
if (linkCount++ > ioMaxLinkLevels)
{
(void) errnoSet (ELOOP);
goto handleErrorWithDecRefCnt;
}
/* lock I/O to prevent from changing the contetnt of the dev header */
(void) iosLock();
/*
* When following links, we do not care about the CWD,
* so use iosDevMatch() instead of iosDevFind().
* If there is no device match, treat this as a link
* inside the same device (*pDevHdr1).
*
* Note that some drivers (e.g. NFS client) return
* FOLLOW_LINK for symlinks entirely within the device
* filesystem. This is somewhat risky, since if an
* internal link happens to start with a VxWorks I/O
* system device name, it will be treated as a
* cross-device link.
*/
pDevHdr2 = iosDevMatch(fullFileName);
if (pDevHdr2 != NULL)
{
pPartFileName = fullFileName + strlen(pDevHdr2->name);
/*
* link file name starts with a vxWorks device name,
* possibly a different device from the current one.
*/
strncpy (fullFileName, pPartFileName, (size_t) MAX_FILENAME_LENGTH);
fullFileName[MAX_FILENAME_LENGTH - 1] = EOS;
strncpy (savedDevName, pDevHdr2->name, MAX_FILENAME_LENGTH);
savedDevName[MAX_FILENAME_LENGTH - 1] = EOS;
if (pDevHdr1 != pDevHdr2)
{
/* increment drvRefCount to prevent from deletion */
if (openDrvRefCntInc (pDevHdr2) != OK)
goto handleErrorWithUnlockDecRefCnt;
(void) iosUnlock();
/* decrement drvRefCount */
openDrvRefCntDec (pDevHdr1);
pDevHdr1 = pDevHdr2;
}
else
{
(void) iosUnlock();
}
}
else
{
/*
* No device match, continue following link under
* same device *pDevHdr1.
*/
(void) iosUnlock();
}
}
#ifdef _WRS_CONFIG_RTP
if (curRtpId != kernelId)
{
/*
* Take RTP lock prior to call iosLock().
*
* The mmanFdMap() takes RTP lock and iosLock() is called while owning
* the RTP lock mutex semaphore through ioctl().
* Since the iosRtpFdSetup() takes RTP lock, we must take RTP lock
* before taking the IOS lock to prevent from a dead lock situation.
*/
if (_func_rtpVerifiedLock (curRtpId) == ERROR)
{
goto handleErrorWithDecRefCnt;
}
rtpIsLocked = TRUE;
}
#endif /* _WRS_CONFIG_RTP */
(void) iosLock();
/* Check if pDevHdr1 has been removed from the IO system. */
if ((pDevHdr1->pDrvEntry == &fdInvalidDrv))
{
/*
* *pDevHdr1 is a zombie device. It has been removed from iosDvList,
* but is not freed yet (since we hold a reference count). pDevHdr1
* was passed to iosCreate() or iosOpen(), which returned successfully,
* so the driver de_create() or de_open() likewise returned
* successfully.
*
* The 'value' returned by the driver routine presumably is linked
* to the device corresponding to *pDevHdr1 in a way that the driver
* understands.
*
* But iosDevDelete() or iosDrvRemove() must have been called to
* remove the device. iosDevDelete() and iosDrvRemove() without
* forceClose try to arrange that "all" fds on the device (or driver)
* are invalidated in such a way that the application can successfully
* call close() on them; but that close() does not result in a call to
* the driver de_close() routine. It is assumed that the driver takes
* care of freeing any driver-level resources associated with the files
* open on the removed device.
*
* If iosDrvRemove() is called with forceClose TRUE, then existing fds
* on the device (not the one we allocated above) are actively closed
* in a way that results in a call to the driver de_close() routine.
* However, always for iosDrvRemove(), the driver slot is invalidated
* and one cannot call even the driver de_close routine subsequently.
*
* Either way, a call to the driver de_close() routine is not
* appropriate here.
*
* Neither is it appropriate to add our new fd to the FD table
* referencing the removed *pDevHdr1.
*
* If the driver has been removed (iosDrvRemove()) then there is nothing
* we can do but fail. Suppose that the driver has not been removed.
*
* If the iosOpen/iosCreate call succeeded BEFORE *pDevHdr1 was removed
* from the IO system, then we must assume the driver will release
* all driver resources associated with *pDevHdr1 when we release the
* *pDevHdr1 reference count below. In particular, we expect that
* the driver will destroy the 'value' returned by the driver de_open()
* or de_create() routine above. So we should not keep a reference
* to this value in the FD table. We should fail in this case.
*
* Note that up to races and memory-ordering issues between CPUs, the
* iosOpen/iosCreate call could not have succeeded AFTER *pDevHdr1 was
* removed, since removal sets pDevHdr1->pDrvEntry to &fdInvalidDrv,
* which sets the relevant de_open() or de_create() routines called by
* iosOpen() or iosCreate() to iosDrvDeleted(), which always fails.
*
* If there is another device in iosDvList with the same name and
* the same driver number, we assume that pDevHdr1 was suspended
* before being removed, and that and iosRmvDrvWaitSuspend()
* switched to the new device (pDevHdr2 below) before calling
* the actual driver de_open() or de_create() entry point, so that
* the returned 'value' actually is based upon pDevHdr2; and
* so we register fd with 'value' and pDevHdr2 in the FD table.
*/
pDevHdr2 = iosDevMatch (savedDevName);
if (pDevHdr2 != NULL
&& 0 == strcmp (pDevHdr2->name, savedDevName)
&& pDevHdr2->drvNum == pDevHdr1->drvNum
&& OK == iosRtpFdSetup (curRtpId, pFdEntry, fd,
pDevHdr2, name, value))
{
pFdEntry->flags = flags;
}
else
{
goto handleErrorWithUnlockDecRefCnt;
}
}
else
{
/*
* The device pDevHdr1, on which we successfully opened the file,
* still exists in the device list. It might be suspended, but we
* don't care here.
*/
if (iosRtpFdSetup (curRtpId, pFdEntry, fd, pDevHdr1, name, value)
== OK)
{
pFdEntry->flags = flags;
}
else
{
goto handleErrorWithUnlockDecRefCnt;
}
}
(void) iosUnlock();
#ifdef _WRS_CONFIG_RTP
if (rtpIsLocked)
{
RTP_UNLOCK (curRtpId);
}
#endif /* _WRS_CONFIG_RTP */
/* decrement drvRefCount */
openDrvRefCntDec (pDevHdr1);
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
EVT_OBJ_STR_2 (pFdEntry, fdClassId,
(event_t) (create ? EVENT_IOCREAT : EVENT_IOOPEN),
fd, flags, strlen (name), name);
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
exit:
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (krnPthreadCnclType, NULL);
KMEM_FREE (fullFileName);
return (fd);
handleErrorWithUnlock:
(void) iosUnlock();
goto handleError;
handleErrorWithUnlockDecRefCnt:
(void) iosUnlock();
#ifdef _WRS_CONFIG_RTP
if (rtpIsLocked)
{
RTP_UNLOCK (curRtpId);
}
#endif /* _WRS_CONFIG_RTP */
handleErrorWithDecRefCnt:
/* decrement drvRefCount */
openDrvRefCntDec (pDevHdr1);
handleError:
iosFdEntryReturn (pFdEntry);
iosRtpFdUnmap2 (curRtpId, fd, unmapFlag);
fd = ERROR;
goto exit;
}
/*******************************************************************************
*
* close - close a file
*
* This routine closes the specified file and frees the file descriptor.
* It calls the device driver to do the work.
*
* RETURNS
* The status of the driver close routine, or ERROR if the file descriptor
* is invalid.
*
* ERRNO
* \is
* \i EBADF
* Invalid file descriptor.
* \i Others
* Other errors generated by device drivers.
* \ie
*/
int close
(
int fd /* file descriptor to close */
)
{
int ret; /* the real close return value */
int krnPthreadCnclType; /* temp kernel canceltype saved value */
#ifdef MEASURE_SYS_CALLS
sysTimestampEnable();
UINT32 startTick = 0, endTick = 0, diffTick = 0;
UINT64 timeUs = 0;
UINT32 freq = tsFreq;
char toMeasure = (measurementFlag && (sysCallTaskID == taskIdSelf()));
if (toMeasure)
{
startTick = sysTimestamp();
(API_STATS[closeCall].sysCallCount)++;
}
#endif
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (PTHREAD_CANCEL_ASYNCHRONOUS,
&krnPthreadCnclType);
ret = iosClose (fd);
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (krnPthreadCnclType, NULL);
#ifdef MEASURE_SYS_CALLS
if (toMeasure)
{
endTick = sysTimestamp();
diffTick = endTick - startTick;
timeUs = ((UINT64)diffTick * 1000000ULL) / freq;
(API_STATS[closeCall].execTimeUsec)+=timeUs;
}
#endif
return (ret);
}
/***************************************************************************
*
* ioReadWrite -
*/
LOCAL ssize_t ioReadWrite
(
ssize_t (*pRdWrtRtn) (int, char *, size_t),
int fd,
char * buffer,
size_t bytes
)
{
ssize_t ret;
int krnPthreadCnclType;
if (NULL == buffer)
{
errnoSet(EINVAL);
return ERROR;
}
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (PTHREAD_CANCEL_ASYNCHRONOUS,
&krnPthreadCnclType);
ret = pRdWrtRtn (fd, buffer, bytes);
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (krnPthreadCnclType, NULL);
return (ret);
}
/*******************************************************************************
*
* read - read bytes from a file or device
*
* This routine reads a number of bytes (less than or equal to <maxbytes>)
* from a specified file descriptor and places them in <buffer>. It calls
* the device driver to do the work.
*
* RETURNS
* The number of bytes read (between 1 and <maxbytes>, 0 if end of file), or
* ERROR if the file descriptor does not exist, the driver does not have
* a read routines, or the driver returns ERROR. If the driver does not
* have a read routine, errno is set to ENOTSUP.
*
* ERRNO
* \is
* \i EBADF
* Bad file descriptor number.
* \i ENOTSUP
* Device driver does not support the read command.
* \i ENXIO
* Device and its driver are removed. close() should be called to release
* this file descriptor.
* \i Other
* Other errors reported by device driver.
* \ie
*/
ssize_t read
(
int fd, /* file descriptor from which to read */
char * buffer, /* pointer to buffer to receive bytes */
size_t maxBytes /* max no. of bytes to read into buffer */
)
{
if (maxBytes == 0)
{
/* POSIX allows for this detection before any other thing. */
return (0);
}
ssize_t result;
#ifdef MEASURE_SYS_CALLS
sysTimestampEnable();
UINT32 startTick = 0, endTick = 0, diffTick = 0;
UINT64 timeUs = 0;
UINT32 freq = tsFreq;
char toMeasure = (measurementFlag && (sysCallTaskID == taskIdSelf()));
if (toMeasure)
{
startTick = sysTimestamp();
(API_STATS[readCall].sysCallCount)++;
}
#endif
result=(ioReadWrite (iosRead, fd, buffer, maxBytes));
#ifdef MEASURE_SYS_CALLS
if (toMeasure)
{
endTick = sysTimestamp();
diffTick = endTick - startTick;
timeUs = ((UINT64)diffTick * 1000000ULL) / freq;
(API_STATS[readCall].execTimeUsec)+=timeUs;
}
#endif
return result;
}
/*******************************************************************************
*
* write - write bytes to a file
*
* This routine writes <nbytes> bytes from <buffer> to a specified file
* descriptor <fd>. It calls the device driver to do the work.
*
* RETURNS
* The number of bytes successfully written,
* or ERROR if the file descriptor does not exist, the driver
* does not have a write routine, or the driver returns ERROR. If the driver
* does not have a write routine, errno is set to ENOTSUP.
*
* ERRNO
* \is
* \i EBADF
* Bad file descriptor number.
* \i ENOTSUP
* Device driver does not support the write command.
* \i ENXIO
* Device and its driver are removed. close() should be called to release
* this file descriptor.
* \i Other
* Other errors reported by device driver.
* \ie
*/
ssize_t write
(
int fd, /* file descriptor on which to write */
char * buffer, /* buffer containing bytes to be written */
size_t nBytes /* number of bytes to write */
)
{
ssize_t result;
#ifdef MEASURE_SYS_CALLS
sysTimestampEnable();
UINT32 startTick = 0, endTick = 0, diffTick = 0;
UINT64 timeUs = 0;
UINT32 freq = tsFreq;
char toMeasure = (measurementFlag && (sysCallTaskID == taskIdSelf()));
if (toMeasure)
{
startTick = sysTimestamp();
(API_STATS[writeCall].sysCallCount)++;
}
#endif
result=(ioReadWrite (iosWrite, fd, buffer, nBytes));
#ifdef MEASURE_SYS_CALLS
if (toMeasure)
{
endTick = sysTimestamp();
diffTick = endTick - startTick;
timeUs = ((UINT64)diffTick * 1000000ULL) / freq;
(API_STATS[writeCall].execTimeUsec)+=timeUs;
}
#endif
return result;
}
/*******************************************************************************
*
* lseek - set a file read/write pointer
*
* This routine sets the file read/write pointer of file <fd>
* to <offset>.
* The argument <whence>, which affects the file position pointer,
* has three values:
*
* \ts
* SEEK_SET (0) |- set to <offset>
* SEEK_CUR (1) |- set to current position plus <offset>
* SEEK_END (2) |- set to the size of the file plus <offset>
* \te
*
* This routine calls ioctl() with functions FIOWHERE, FIONREAD, and FIOSEEK,
* and their 64bit version FIOWHERE64, FIONREAD64 and FIOSEEK64.
*
* RETURNS:
* The new offset from the beginning of the file, or ERROR.
*
* ERRORS:
* EINVAL is set if the whence parameter is invalid, or if seek negative
* position of the file.
* EOVERFLOW is set if seek position exceed 32-bit value range.
* Other errors may be set by the io system or device drivers.
*/
off_t lseek
(
int fd, /* file descriptor */
off_t offset, /* new byte offset to seek to */
int whence /* relative file position */
)
{
BOOL must64 = FALSE;
int where = 0;
unsigned int nBytes = 0;
long long offset64 = offset;
long long where64 = 0;
unsigned long long nBytes64 = 0;
struct stat myStat;
switch (whence)
{
case SEEK_SET:
offset64 = offset;
break;
case SEEK_CUR:
/* get the current position */
if (ioctl (fd, FIOWHERE64, (_Vx_ioctl_arg_t) & where64) == ERROR)
{
/* goes to FIOWHERE */
if ((where = ioctl (fd, FIOWHERE, 0)) == ERROR)
return ((off_t)ERROR);
else
where64 = (unsigned int)where;
}
offset64 = where64 + offset;
break;
case SEEK_END:
if (ioctl (fd, FIOFSTATGET, (_Vx_ioctl_arg_t)&myStat) == ERROR)
{
/* can not get the file size */
/* for those devcie which do not support FIOFSTATGET, we should try the old method for compatibility. */
/* seek to the begining of the file */
where64 = 0;
if (ioctl (fd, FIOSEEK64, (_Vx_ioctl_arg_t) & where64) == ERROR)
{
/* goes to FIOSEEK */
if (ioctl (fd, FIOSEEK, 0) == ERROR)
{
return ((off_t)ERROR);
}
}
/* get the size of the file */
if (ioctl (fd, FIONREAD64, (_Vx_ioctl_arg_t) & nBytes64) == ERROR)
{
/* goes to FIONREAD */
nBytes = 0;
if (ioctl (fd, FIONREAD, (_Vx_ioctl_arg_t) & nBytes) == ERROR)
{
return ((off_t)ERROR);
}
else
{
nBytes64 = nBytes;
}
}
}
else
{
/* get the file size */
nBytes64 = myStat.st_size;
}
offset64 += nBytes64;
break;
default:
goto seekErr;
}/* switch (where) */
if (offset64 < 0)
goto seekErr;
/* If the given offset is beyond 32 bits, the 64 bit ioctls must work */
must64 = (offset64 > (unsigned int)UINT_MAX) ? TRUE : FALSE ;
#ifndef _WRS_CONFIG_LP64
/* On vxWorks 32-bit, offset64 should not exceed UINT_MAX - 1,
* since the return value type is 32-bit limited in kernel side.
* and UINT_MAX(-1) reserved for status ERROR.
*/
if (offset64 > ((unsigned int)UINT_MAX - 1))
{
errnoSet(EOVERFLOW);
return (ERROR);
}
#endif
if (must64)
{
if (ioctl (fd, FIOSEEK64, (_Vx_ioctl_arg_t)&offset64) == ERROR)
return ((off_t)ERROR);
else
return ((off_t)offset64);
}
else
{
if (ioctl(fd, FIOSEEK, (_Vx_ioctl_arg_t)offset64) == ERROR)
{
/* goes to FIOSEEK64 if get errno ENOTSUP */
if (errno == ENOTSUP)
{
if (ioctl (fd, FIOSEEK64, (_Vx_ioctl_arg_t)&offset64) == ERROR)
return ((off_t)ERROR);
else
return ((off_t)offset64);
}
else
return ((off_t)ERROR);
}
else
return ((off_t)offset64);
} /* must64 */
seekErr:
errno = EINVAL;
return ((off_t)ERROR);
} /* lseek() */
/*******************************************************************************
*
* ioctl - perform an I/O control function
*
* This routine performs an I/O control function on a device. The control
* functions used by VxWorks device drivers are defined in the header file
* ioLib.h. Most requests are passed on to the driver for handling.
* Since the availability of ioctl() functions is driver-specific, these
* functions are discussed separately in tyLib, pipeDrv, nfsDrv, dosFsLib,
* and rawFsLib.
*
* The third argument is optional, _Vx_ioctl_arg_t type is recommended,
* then for VxWorks 32-bits, this is a 32-bits type, and for VxWorks 64-bits,
* this is a 64-bits type.
*
* The following example renames the file or directory to the string "newname":
*
* \cs
* ioctl (fd, FIORENAME, "newname");
* \ce
*
* Note that the function FIOGETNAME is handled by the I/O interface level and
* is not passed on to the device driver itself. Thus this function code value
* should not be used by customer-written drivers. This ioctl code is convenient
* for checking the validity of any fd number. The following example shows how
* to quickly validate a given fd number as being valid.
*
* \cs
* if (ioctl (fd, FIOGETNAME, NULL) == ERROR)
* {
* /@ fd is not valid @/
* }
* \ce
*
* RETURNS
* The return value of the driver, or ERROR if the file descriptor does
* not exist.
*
* ERRNO
* \is
* \i EBADF
* Bad file descriptor number.
* \i S_ioLib_UNKNOWN_REQUEST (ENOSYS)
* Device driver does not support the ioctl command.
* \i ENOTSUP
* Device driver supports the ioctl command but not all optional features
* \i ENXIO
* Device and its driver are removed. close() should be called to release
* this file descriptor.
* \i Other
* Other errors reported by device driver.
* \ie
*
* SEE ALSO: tyLib, pipeDrv, nfsDrv, dosFsLib, rawFsLib,
* the VxWorks programmer guides.
*/
int ioctl
(
int fd, /* file descriptor */
int function, /* function code */
...
)
{
va_list vaList;
_Vx_ioctl_arg_t arg;
/*
* Should do something more clever than "always grab one more int"
* here, but this suffices for now to fix WIND00060945.
*/
va_start (vaList, function);
arg = va_arg (vaList, _Vx_ioctl_arg_t);
va_end (vaList);
/*
* syscall flag set to false because ioctl from user side
* will not call ioctl().
*/
return (iosIoctlInternal (fd, function, arg, FALSE));
}
/*******************************************************************************
*
* readv - read data from a device into scattered buffers
*
* readv takes as a parameter a list of buffers (iov) into which it should
* place data read from the specified file descriptor (fd). iov is a pointer
* to an array of length iovcnt of (struct iovec) structures, which describe
* the location and length of each individual buffer. readv will always
* completely fill a buffer before moving on to the next buffer in the list.
*
* RETURNS
* Number of bytes read (0 if end of file), or
* ERROR if the file descriptor does not exist or the driver returns ERROR.
*
* ERRNO
* See read().
*
* \NOMANUAL
*/
ssize_t readv
(
int fd, /* file descriptor */
struct iovec *iov, /* buffer list */
int iovcnt /* number of elements in buffer list */
)
{
int i;
char *pBuf;
size_t bytesToRead;
ssize_t totalBytesRead = 0;
ssize_t bytesRead;
int krnPthreadCnclType; /* temp kernel canceltype saved value */
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (PTHREAD_CANCEL_ASYNCHRONOUS,
&krnPthreadCnclType);
for (i = 0; i < iovcnt; i++)
{
pBuf = (char *) iov[i].iov_base;
bytesToRead = iov[i].iov_len;
while (bytesToRead > 0)
{
if ((bytesRead = iosRead (fd, pBuf, bytesToRead)) == ERROR)
{
if (totalBytesRead == 0)
totalBytesRead = ERROR;
goto readvDone;
}
if (bytesRead == 0)
goto readvDone;
totalBytesRead += bytesRead;
bytesToRead = bytesToRead - (size_t)bytesRead;
pBuf += bytesRead;
}
}
readvDone:
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (krnPthreadCnclType, NULL);
return (totalBytesRead);
}
/*******************************************************************************
*
* writev - write data from scattered buffers to a device
*
* writev takes as a parameter a list of buffers (iov) from which it should
* write data to the specified file descriptor (fd). iov is a pointer
* to an array of length iovcnt of (struct iovec) structures, which describe
* the location and length of each individual buffer. writev will always
* completely empty a buffer before moving on to the next buffer in the list.
*
* RETURNS
* Number of bytes written, or
* ERROR if the file descriptor does not exist or the driver returns ERROR.
*
* ERRNO
* See write().
*
* \NOMANUAL
*/
ssize_t writev
(
int fd,
register struct iovec *iov,
int iovcnt
)
{
int i;
char *pData;
size_t bytesToWrite;
ssize_t totalBytesWritten = 0;
ssize_t bytesWritten;
int krnPthreadCnclType; /* temp kernel canceltype saved value */
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (PTHREAD_CANCEL_ASYNCHRONOUS,
&krnPthreadCnclType);
for (i = 0; i < iovcnt; i++)
{
pData = (char *) iov[i].iov_base;
bytesToWrite = iov[i].iov_len;
while (bytesToWrite > 0)
{
if ((bytesWritten = iosWrite (fd, pData, bytesToWrite)) == ERROR)
{
if (totalBytesWritten == 0)
totalBytesWritten = ERROR;
goto writevDone;
}
totalBytesWritten += bytesWritten;
bytesToWrite = bytesToWrite - (size_t)bytesWritten;
pData += bytesWritten;
}
}
writevDone:
if (_func_pthread_testandset_canceltype != NULL)
_func_pthread_testandset_canceltype (krnPthreadCnclType, NULL);
return (totalBytesWritten);
}
/*******************************************************************************
*
* ioFullFileNameGet - resolve path name to device and full file name
*
* This routine resolves the specified path name into a device and full
* filename on that device. If the specified path name is not a full,
* absolute path name, then it is concatenated to the current default
* path to derive a full path name. This full path name is separated
* into the device specification and the remaining filename on that device.
* A pointer to the device header is returned in <ppDevHdr> and the
* filename on that device is returned in <fullFileName>.
*
* RETURNS
* OK, or
* ERROR if the full filename has more than MAX_FILENAME_LENGTH characters.
*
* ERRNO
* \is
* \i S_ioLib_DEVICE_NOT_FOUND (ENODEV)
* No device found in pathName.
* \ie
*
* \NOMANUAL
*/
STATUS ioFullFileNameGet
(
const char *pathName, /* path name */
DEV_HDR ** ppDevHdr, /* ptr to dev hdr to complete */
char * fullFileName /* resulting complete filename */
)
{
const char * pTail;
char * ffn;
size_t maxPathLen = MAX_FILENAME_LENGTH;
bzero (fullFileName, maxPathLen); /* initialize buffer to 0 */
/* resolve default path plus partial pathname to full path name */
IOS_CWD_LOCK_COND(); /* protecting the global CWD conditionally */
if (pathCat (CUR_WORK_DIR, pathName, fullFileName) == ERROR)
{
IOS_CWD_UNLOCK_COND();
return (ERROR);
}
IOS_CWD_UNLOCK_COND();
/* If in PSE52 mode, more than 2 leading slashes become just one */
ffn = fullFileName;
if (iosPse52Mode)
{
int idx;
for (idx = 0; ffn[idx] == '/'; ++idx)
;
if (idx > 2)
{
idx--;
ffn += idx;
}
}
/* remove device name from full path name */
if ((*ppDevHdr = iosDevFind (ffn, &pTail)) == NULL)
return (ERROR);
/* Remove the device head part of the full path. */
strncpy (fullFileName, pTail, maxPathLen);
fullFileName[MAX_FILENAME_LENGTH - 1] = EOS;
return (OK);
}
/*******************************************************************************
*
* ioGlobalStdSet - set file descriptor for global input/output/error
*
* This routine changes the assignment of a specified global standard file
* descriptor <stdFd> (0, 1, or, 2) to the specified underlying file
* descriptor <newFd>. <newFd> should be a file descriptor open to the
* desired device or file. All tasks will use this new assignment when doing
* I/O to <stdFd>, unless they have specified a task-specific standard file
* descriptor (see ioTaskStdSet()). If <stdFd> is not 0, 1, or 2, this
* routine has no effect.
*
* RETURNS: OK, or ERROR if input data is not valid.
*
* ERRNO
* \is
* \i EBADF
* The newFd does not represent a valid open file.
* \i EINVAL
* The stdFd value is not valid.
* \ie
*
*
* SEE ALSO: ioGlobalStdGet(), ioTaskStdSet()
*/
STATUS ioGlobalStdSet
(
int stdFd, /* std input (0), output (1), or error (2) */
int newFd /* new underlying file descriptor */
)
{
if (iosFdMap (newFd) == NULL)
return (ERROR); /* EBADF */
/* For base6 RTP, this is a dup2 operation */
/* Need validation of newFd */
if (STD_VALID (stdFd) && CUR_RTP_ID == kernelId)
{
ioStdFd[stdFd] = newFd;
if (stdFd == 1)
_func_consoleOut = write;
return (OK);
}
errno = EINVAL;
return (ERROR);
}
/*******************************************************************************
*
* ioGlobalStdGet - get the file descriptor for global input/output/error
*
* This routine returns the current underlying file descriptor for global
* standard input, output, and error.
*
* RETURNS
* The underlying global file descriptor, or ERROR if <stdFd> is not 0, 1, or 2.
*
* ERRNO: N/A.
*
* SEE ALSO: ioGlobalStdSet(), ioTaskStdGet()
*/
int ioGlobalStdGet
(
int stdFd /* std input (0), output (1), or error (2) */
)
{
if (CUR_RTP_ID != kernelId)
return (stdFd);
return (STD_VALID (stdFd) ? ioStdFd[stdFd] : ERROR);
}
/*******************************************************************************
*
* ioTaskStdSet - set the file descriptor for task standard input/output/error
*
* This routine changes the assignment of a specified task-specific standard
* file descriptor <stdFd> (0, 1, or, 2) to the specified underlying file
* descriptor<newFd>. <newFd> should be a file descriptor open to the
* desired device or file. The calling task will use this new assignment
* when doing I/O to <stdFd>, instead of the system-wide global assignment
* which is used by default. If <stdFd> is not 0, 1, or 2, this routine has
* no effect.
*
* NOTE: This routine has no effect if it is called at interrupt level.
*
* RETURNS: OK, or ERROR if input data is not valid.
*
* ERRNO
* \is
* \i EBADF
* The newFd does not represent a valid open file.
* \i EINVAL
* The stdFd or taskId values are not valid.
* \ie
*
* SEE ALSO: ioGlobalStdGet(), ioTaskStdGet()
*/
STATUS ioTaskStdSet
(
TASK_ID taskId, /* task whose std fd is to be set (0 = self) */
int stdFd, /* std input (0), output (1), or error (2) */
int newFd /* new underlying file descriptor */
)
{
WIND_TCB * pTcb;
if (iosFdMap (newFd) == NULL)
return (ERROR); /* EBADF, newFd not an open fd */
/* Only valid if rtpId = kernelId */
if (STD_VALID (stdFd) && (pTcb = taskTcb (taskId)) != NULL &&
pTcb->rtpId == kernelId)
{
pTcb->taskStd[stdFd] = newFd;
if (stdFd == 1)
_func_consoleOut = write;
return (OK);
}
errno = EINVAL;
return (ERROR); /* EINVAL, stdFd, or taskId is bad */
}
/*******************************************************************************
*
* ioTaskStdGet - get the file descriptor for task standard input/output/error
*
* This routine returns the current underlying file descriptor for task-specific
* standard input, output, and error.
*
* RETURNS
* The underlying file descriptor, or ERROR if <stdFd> is not 0, 1, or 2, or
* the routine is called at interrupt level.
*
* ERRNO:
* \is
* \i S_intLib_NOT_ISR_CALLABLE
* Routine is not callable from an ISR.
* \ie
*
* SEE ALSO: ioGlobalStdGet(), ioTaskStdSet()
*/
int ioTaskStdGet
(
TASK_ID taskId, /* ID of desired task (0 = self) */
int stdFd /* std input (0), output (1), or error (2) */
)
{
WIND_TCB * pTcb;
int taskFd;
if (_WRS_INT_RESTRICT () != OK)
{
return (ERROR);
}
/* Only remap if rtpId == kernelId, */
if (STD_VALID (stdFd) && (pTcb = taskTcb (taskId)) != NULL)
{
if (pTcb->rtpId != kernelId)
return (stdFd); /* no remapping of RTP fd's */
taskFd = pTcb->taskStd[stdFd];
if (STD_VALID (taskFd))
return (ioStdFd[taskFd]);
else
return (taskFd);
}
return (ERROR);
}
/***************************************************************************
*
* isatty - return whether the underlying driver is a tty device
*
* This routine simply invokes the ioctl() function FIOISATTY on the
* specified file descriptor.
*
* RETURNS: TRUE, or FALSE if the driver does not indicate a tty device.
*
* ERRNO: See ioctl().
*/
BOOL isatty
(
int fd /* file descriptor to check */
)
{
return (ioctl (fd, FIOISATTY, 0) == TRUE);
}
/***********************************************************************
*
* fcntl - perform control functions over open files
*
* SYNOPSIS
* \cs
* int fcntl
* (
* int fd,
* int command,
* ...
* )
* \ce
*
* DESCRIPTION
* The fcntl() function provides for control over open files.
* The <fd> argument is an open file descriptor. The fcntl() function may
* take a third argument whose data type, value and use depend upon the
* value of <command> which specifies the operation to be performed by
* fcntl().
*
* ERRNO:
* \is
* \i EMFILE
* Ran out of file descriptors
* \i EBADF
* Bad file descriptor number.
* \i ENOSYS
* Device driver does not support the ioctl command.
* \i ENXIO
* Device and its driver are removed. close() should be called to release
* this file descriptor.
* \i Other
* Other errors reported by device driver.
* \ie
*
* SEE ALSO:
*/
int fcntl
(
int fd, /* file descriptor */
int command, /* function code */
...
)
{
va_list vaList;
FCNTL_ARG arg;
int temp;
int ret;
va_start (vaList, command);
if (command == F_DUPFD)
{
if (_func_fcntl_dup != NULL)
{
temp = va_arg (vaList, int);
ret = _func_fcntl_dup (fd, temp);
}
else
{
errno = ENOTSUP;
ret = ERROR;
}
}
else if (command == F_GETFD)
{
ret = FD_CLOEXEC;
}
else if (command == F_SETFD)
{
temp = va_arg (vaList, int);
if (temp != 0 && temp != FD_CLOEXEC)
{
errno = EINVAL;
ret = ERROR;
}
else
{
ret = OK;
}
}
else if (command == F_GETFL)
{
arg.command = F_GETFL;
arg.data = (void *) &temp;
if (ioctl (fd, FIOFCNTL, (_Vx_ioctl_arg_t) &arg) == ERROR)
ret = ERROR;
else
ret = temp;
}
else if (command == F_SETFL)
{
temp = va_arg (vaList, int);
arg.command = F_SETFL;
arg.data = (void *) &temp;
if (ioctl (fd, FIOFCNTL, (_Vx_ioctl_arg_t) &arg) == ERROR)
ret = ERROR;
else
ret = OK;
}
else if (command == F_GETLK ||
command == F_SETLK ||
command == F_SETLKW)
{
arg.command = command;
arg.data = va_arg (vaList, struct flock *);
if (ioctl (fd, FIOFCNTL, (_Vx_ioctl_arg_t) &arg) == ERROR)
ret = ERROR;
else
ret = OK;
}
else
{
errno = EINVAL;
ret = ERROR;
}
va_end (vaList);
return (ret);
}
/***************************************************************************
*
* openDrvRefCntInc - increase reference count for removable device
*
* This routine increases reference count for removable device.
*
* This routine is only used by ioCreateOrOpen(). The I/O data structure
* exclusion and <pDevHdr> NULL pointer test must be done prior to call this
* function.
* The removable device test is done inside this function prior to call
* iosOpenDrvRefCntInc().
*
* RETURNS: OK or ERROR if the device is removable and already invalidated.
*
* \NOMANUAL
*/
LOCAL STATUS openDrvRefCntInc
(
DEV_HDR * pDevHdr
)
{
if ((pDevHdr->drvRefFlag & DEV_HDR_REMOVABLE) &&
(_func_iosOpenDrvRefCntInc != NULL))
{
return (_func_iosOpenDrvRefCntInc (pDevHdr));
}
return (OK);
}
/***************************************************************************
*
* openDrvRefCntDec - decrease reference count for removable device
*
* This routine decreases reference count for removable device.
* If the reference count is zero (or negative) and the device is already
* invalidated, the driver will be deleted.
*
* This routine is only used by ioCreateOrOpen(). The <pDevHdr> must not be
* NULL that is made sure by the ioCreateOrOpen() prior to call this function.
* The I/O data structure exclusion and removable device test will be done by
* the iosOpenDrvRefCntDec().
*
* RETURNS: N/A
*
* \NOMANUAL
*/
LOCAL void openDrvRefCntDec
(
DEV_HDR * pDevHdr
)
{
if (_func_iosOpenDrvRefCntDec != NULL)
{
return (_func_iosOpenDrvRefCntDec (pDevHdr));
}
}