Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/41 Co-authored-by: siddhant <siddhant.singh@neominds.in> Co-committed-by: siddhant <siddhant.singh@neominds.in>
2116 lines
68 KiB
C
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));
|
|
}
|
|
}
|