From 529f108360089e2cc8752c051df43024ea833930 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 2 Sep 2005 15:40:52 +0000 Subject: 2005-09-02 Joel Sherrill * bit, ncurses-5.3/misc/run_tic.sh: Added rtemsNfs 1.2 * rtemsNfs/ChangeLog, rtemsNfs/LICENSE, rtemsNfs/Makefile, rtemsNfs/README, rtemsNfs/rtems-filesystem-patch, rtemsNfs/proto/Makefile, rtemsNfs/proto/mount_prot.h, rtemsNfs/proto/mount_prot.x, rtemsNfs/proto/mount_prot_xdr.c, rtemsNfs/proto/nfs_prot.h, rtemsNfs/proto/nfs_prot.x, rtemsNfs/proto/nfs_prot_xdr.c, rtemsNfs/src/Makefile, rtemsNfs/src/cexphelp.c, rtemsNfs/src/dirutils.c, rtemsNfs/src/librtemsNfs.h, rtemsNfs/src/nfs.c, rtemsNfs/src/nfs.modini.c, rtemsNfs/src/rpcio.c, rtemsNfs/src/rpcio.h, rtemsNfs/src/rpcio.modini.c, rtemsNfs/src/sock_mbuf.c, rtemsNfs/src/xdr_mbuf.c: New files. * rtemsNfs-1.1/ChangeLog, rtemsNfs-1.1/LICENSE, rtemsNfs-1.1/Makefile, rtemsNfs-1.1/README, rtemsNfs-1.1/rtems-filesystem-patch, rtemsNfs-1.1/proto/Makefile, rtemsNfs-1.1/proto/mount_prot.x, rtemsNfs-1.1/proto/nfs_prot.x, rtemsNfs-1.1/src/Makefile, rtemsNfs-1.1/src/cexphelp.c, rtemsNfs-1.1/src/dirutils.c, rtemsNfs-1.1/src/librtemsNfs.h, rtemsNfs-1.1/src/nfs.c, rtemsNfs-1.1/src/nfs.modini.c, rtemsNfs-1.1/src/rpcio.c, rtemsNfs-1.1/src/rpcio.h, rtemsNfs-1.1/src/rpcio.modini.c, rtemsNfs-1.1/src/sock_mbuf.c, rtemsNfs-1.1/src/xdr_mbuf.c: Removed. --- ChangeLog | 24 + bit | 3 +- ncurses-5.3/misc/run_tic.sh | 2 +- rtemsNfs-1.1/ChangeLog | 30 - rtemsNfs-1.1/LICENSE | 115 -- rtemsNfs-1.1/Makefile | 16 - rtemsNfs-1.1/README | 491 ------ rtemsNfs-1.1/proto/Makefile | 75 - rtemsNfs-1.1/proto/mount_prot.x | 161 -- rtemsNfs-1.1/proto/nfs_prot.x | 1268 ------------- rtemsNfs-1.1/rtems-filesystem-patch | 860 --------- rtemsNfs-1.1/src/Makefile | 104 -- rtemsNfs-1.1/src/cexphelp.c | 16 - rtemsNfs-1.1/src/dirutils.c | 323 ---- rtemsNfs-1.1/src/librtemsNfs.h | 158 -- rtemsNfs-1.1/src/nfs.c | 3299 ---------------------------------- rtemsNfs-1.1/src/nfs.modini.c | 27 - rtemsNfs-1.1/src/rpcio.c | 1717 ------------------ rtemsNfs-1.1/src/rpcio.h | 205 --- rtemsNfs-1.1/src/rpcio.modini.c | 15 - rtemsNfs-1.1/src/sock_mbuf.c | 279 --- rtemsNfs-1.1/src/xdr_mbuf.c | 534 ------ rtemsNfs/ChangeLog | 37 + rtemsNfs/LICENSE | 115 ++ rtemsNfs/Makefile | 16 + rtemsNfs/README | 491 ++++++ rtemsNfs/proto/Makefile | 75 + rtemsNfs/proto/mount_prot.h | 144 ++ rtemsNfs/proto/mount_prot.x | 161 ++ rtemsNfs/proto/mount_prot_xdr.c | 124 ++ rtemsNfs/proto/nfs_prot.h | 453 +++++ rtemsNfs/proto/nfs_prot.x | 1268 +++++++++++++ rtemsNfs/proto/nfs_prot_xdr.c | 671 +++++++ rtemsNfs/rtems-filesystem-patch | 860 +++++++++ rtemsNfs/src/Makefile | 104 ++ rtemsNfs/src/cexphelp.c | 16 + rtemsNfs/src/dirutils.c | 323 ++++ rtemsNfs/src/librtemsNfs.h | 158 ++ rtemsNfs/src/nfs.c | 3317 +++++++++++++++++++++++++++++++++++ rtemsNfs/src/nfs.modini.c | 27 + rtemsNfs/src/rpcio.c | 1717 ++++++++++++++++++ rtemsNfs/src/rpcio.h | 205 +++ rtemsNfs/src/rpcio.modini.c | 15 + rtemsNfs/src/sock_mbuf.c | 279 +++ rtemsNfs/src/xdr_mbuf.c | 534 ++++++ 45 files changed, 11137 insertions(+), 9695 deletions(-) delete mode 100644 rtemsNfs-1.1/ChangeLog delete mode 100644 rtemsNfs-1.1/LICENSE delete mode 100644 rtemsNfs-1.1/Makefile delete mode 100644 rtemsNfs-1.1/README delete mode 100644 rtemsNfs-1.1/proto/Makefile delete mode 100644 rtemsNfs-1.1/proto/mount_prot.x delete mode 100644 rtemsNfs-1.1/proto/nfs_prot.x delete mode 100644 rtemsNfs-1.1/rtems-filesystem-patch delete mode 100644 rtemsNfs-1.1/src/Makefile delete mode 100644 rtemsNfs-1.1/src/cexphelp.c delete mode 100644 rtemsNfs-1.1/src/dirutils.c delete mode 100644 rtemsNfs-1.1/src/librtemsNfs.h delete mode 100644 rtemsNfs-1.1/src/nfs.c delete mode 100644 rtemsNfs-1.1/src/nfs.modini.c delete mode 100644 rtemsNfs-1.1/src/rpcio.c delete mode 100644 rtemsNfs-1.1/src/rpcio.h delete mode 100644 rtemsNfs-1.1/src/rpcio.modini.c delete mode 100644 rtemsNfs-1.1/src/sock_mbuf.c delete mode 100644 rtemsNfs-1.1/src/xdr_mbuf.c create mode 100644 rtemsNfs/ChangeLog create mode 100644 rtemsNfs/LICENSE create mode 100644 rtemsNfs/Makefile create mode 100644 rtemsNfs/README create mode 100644 rtemsNfs/proto/Makefile create mode 100644 rtemsNfs/proto/mount_prot.h create mode 100644 rtemsNfs/proto/mount_prot.x create mode 100644 rtemsNfs/proto/mount_prot_xdr.c create mode 100644 rtemsNfs/proto/nfs_prot.h create mode 100644 rtemsNfs/proto/nfs_prot.x create mode 100644 rtemsNfs/proto/nfs_prot_xdr.c create mode 100644 rtemsNfs/rtems-filesystem-patch create mode 100644 rtemsNfs/src/Makefile create mode 100644 rtemsNfs/src/cexphelp.c create mode 100644 rtemsNfs/src/dirutils.c create mode 100644 rtemsNfs/src/librtemsNfs.h create mode 100644 rtemsNfs/src/nfs.c create mode 100644 rtemsNfs/src/nfs.modini.c create mode 100644 rtemsNfs/src/rpcio.c create mode 100644 rtemsNfs/src/rpcio.h create mode 100644 rtemsNfs/src/rpcio.modini.c create mode 100644 rtemsNfs/src/sock_mbuf.c create mode 100644 rtemsNfs/src/xdr_mbuf.c diff --git a/ChangeLog b/ChangeLog index 77288b6..a52c4fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2005-09-02 Joel Sherrill + + * bit, ncurses-5.3/misc/run_tic.sh: Added rtemsNfs 1.2 + * rtemsNfs/ChangeLog, rtemsNfs/LICENSE, rtemsNfs/Makefile, + rtemsNfs/README, rtemsNfs/rtems-filesystem-patch, + rtemsNfs/proto/Makefile, rtemsNfs/proto/mount_prot.h, + rtemsNfs/proto/mount_prot.x, rtemsNfs/proto/mount_prot_xdr.c, + rtemsNfs/proto/nfs_prot.h, rtemsNfs/proto/nfs_prot.x, + rtemsNfs/proto/nfs_prot_xdr.c, rtemsNfs/src/Makefile, + rtemsNfs/src/cexphelp.c, rtemsNfs/src/dirutils.c, + rtemsNfs/src/librtemsNfs.h, rtemsNfs/src/nfs.c, + rtemsNfs/src/nfs.modini.c, rtemsNfs/src/rpcio.c, + rtemsNfs/src/rpcio.h, rtemsNfs/src/rpcio.modini.c, + rtemsNfs/src/sock_mbuf.c, rtemsNfs/src/xdr_mbuf.c: New files. + * rtemsNfs-1.1/ChangeLog, rtemsNfs-1.1/LICENSE, rtemsNfs-1.1/Makefile, + rtemsNfs-1.1/README, rtemsNfs-1.1/rtems-filesystem-patch, + rtemsNfs-1.1/proto/Makefile, rtemsNfs-1.1/proto/mount_prot.x, + rtemsNfs-1.1/proto/nfs_prot.x, rtemsNfs-1.1/src/Makefile, + rtemsNfs-1.1/src/cexphelp.c, rtemsNfs-1.1/src/dirutils.c, + rtemsNfs-1.1/src/librtemsNfs.h, rtemsNfs-1.1/src/nfs.c, + rtemsNfs-1.1/src/nfs.modini.c, rtemsNfs-1.1/src/rpcio.c, + rtemsNfs-1.1/src/rpcio.h, rtemsNfs-1.1/src/rpcio.modini.c, + rtemsNfs-1.1/src/sock_mbuf.c, rtemsNfs-1.1/src/xdr_mbuf.c: Removed. + 2004-10-18 Joel Sherrill * VERSION: Updated to rtems-addon-packages-4.6.2. diff --git a/bit b/bit index ec68c19..772994a 100755 --- a/bit +++ b/bit @@ -9,7 +9,8 @@ # set -ex -PACKAGES="rtemsNfs-1.1 avl-1.4.0 ncurses-5.3 readline-4.3 libtecla-1.4.1 zlib-1.1.4" +# rtemsNfs is version 1.2 +PACKAGES="rtemsNfs avl-1.4.0 ncurses-5.3 readline-4.3 libtecla-1.4.1 zlib-1.1.4" for p in $PACKAGES do diff --git a/ncurses-5.3/misc/run_tic.sh b/ncurses-5.3/misc/run_tic.sh index 7fa11bb..a366356 100644 --- a/ncurses-5.3/misc/run_tic.sh +++ b/ncurses-5.3/misc/run_tic.sh @@ -43,7 +43,7 @@ echo '** Building terminfo database, please wait...' : ${suffix=} : ${DESTDIR=} -: ${prefix=/opt/rtems/m68k-rtems} +: ${prefix=/opt/rtems-test/powerpc-rtems} : ${exec_prefix=${prefix}} : ${bindir=${exec_prefix}/bin} : ${top_srcdir=..} diff --git a/rtemsNfs-1.1/ChangeLog b/rtemsNfs-1.1/ChangeLog deleted file mode 100644 index c360c9f..0000000 --- a/rtemsNfs-1.1/ChangeLog +++ /dev/null @@ -1,30 +0,0 @@ -Changes since RTEMS-NFS 1.3.beta - NFS: - - fixed possible string overrun in nfsMount - - nfs_read_dir() must reset the 'eofreached' flag if it skipped - dirents present in the xdr but not fitting into the user buffer. - - nfsMountsShow() released the wrong lock! - RPCIO: - - cannot delete locked binary semaphore (authlock) -- must unlock - first (authlock was never deleted and hence effectively leaked) - - added ASSERT paranoia around mutex primitives - - Relaxed paranoia check / ASSERTion failure: - paranoia_free() is called more than once on an ext_buf - it must - undo calls to paranoia_refcnt() - hence the 0 == --refcnt check - is too strict. - - Added a DEBUG flag to introduce random packet losses for testing - retransmission. - xdr_mbuf: - - make sure we do a signed comparison - -Changes since rtemsNFS-1.0.beta2: - - moved 'tar' command to the 'config' area; use - predefined 'make-tar' in individual Makefiles - - use INSTALL_CHANGE for headers, not INSTALL_VARIANT (probably doesn't - matter, though) - - use LD not LD_FOR_TARGET (to get absolute path) - - fixed assertion failure print format - - print requestor id if send_event fails - had just experienced this :-( - - hint about fprintf using FP registers is probably PPC specific - - provided implementation for xdrmbuf_getlong_aligned(). i386-rtems - seems to use it. diff --git a/rtemsNfs-1.1/LICENSE b/rtemsNfs-1.1/LICENSE deleted file mode 100644 index ba677ea..0000000 --- a/rtemsNfs-1.1/LICENSE +++ /dev/null @@ -1,115 +0,0 @@ - - EPICS Open License Terms - - The following is the text of the EPICS Open software license agreement - which applies to many of the unbundled EPICS extensions and support - modules. - - -------------------------------------------------------------- - - Copyright © 2002, Stanford University and - Till Straumann - - RTEMS-NFS is distributed subject to the following license conditions: - - SOFTWARE LICENSE AGREEMENT - Software: RTEMS-NFS - - 1. The "Software", below, refers to RTEMS-NFS (in either source - code, or binary form and accompanying documentation). Each - licensee is addressed as "you" or "Licensee." - - RTEMS-NFS comprises all files under this directory with - the EXCEPTION OF - src/sock_mbuf.c - src/xdr_mbuf.c - proto/mount_prot.x - proto/nfs_prot.x - which are covered by the licenses described in the - LICENSE.NET and LICENSE.RPCXDR files (RTEMS source topdir) - and header comments in the mentioned files, respectively. - - 2. The copyright holders shown above and their third-party - licensors hereby grant Licensee a royalty-free nonexclusive - license, subject to the limitations stated herein and U.S. - Government license rights. - 3. You may modify and make a copy or copies of the Software for use - within your organization, if you meet the following conditions: - a. Copies in source code must include the copyright notice - and this Software License Agreement. - b. Copies in binary form must include the copyright notice - and this Software License Agreement in the documentation - and/or other materials provided with the copy. - - 4. You may modify a copy or copies of the Software or any portion - of it, thus forming a work based on the Software, and distribute - copies of such work outside your organization, if you meet all - of the following conditions: - a. Copies in source code must include the copyright notice - and this Software License Agreement; - b. Copies in binary form must include the copyright notice - and this Software License Agreement in the documentation - and/or other materials provided with the copy; - c. Modified copies and works based on the Software must carry - prominent notices stating that you changed specified - portions of the Software. - - 5. Portions of the Software resulted from work developed under a - U.S. Government contract and are subject to the following - license: the Government is granted for itself and others acting - on its behalf a paid-up, nonexclusive, irrevocable worldwide - license in this computer software to reproduce, prepare - derivative works, and perform publicly and display publicly. - 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT - WARRANTY OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY - LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF - ENERGY, AND THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, - TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY - OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS - OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE - WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT - THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS - ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. - 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, - THEIR THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED - STATES DEPARTMENT OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR - ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE - DAMAGES OF ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS - OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER - SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT - (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, EVEN - IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE POSSIBILITY OF - SUCH LOSS OR DAMAGES. - - Stanford Notice - *************** - - Acknowledgement of sponsorship - - - - - - - - - - - - - - - - - - This software was produced by the Stanford Linear Accelerator Center, - Stanford University, under Contract DE-AC03-76SFO0515 with the Department - of Energy. - - Government disclaimer of liability - - - - - - - - - - - - - - - - - - - Neither the United States nor the United States Department of Energy, - nor any of their employees, makes any warranty, express or implied, - or assumes any legal liability or responsibility for the accuracy, - completeness, or usefulness of any data, apparatus, product, or process - disclosed, or represents that its use would not infringe privately - owned rights. - - Stanford disclaimer of liability - - - - - - - - - - - - - - - - - - - Stanford University makes no representations or warranties, express or - implied, nor assumes any liability for the use of this software. - - Maintenance of notice - - - - - - - - - - - - - In the interest of clarity regarding the origin and status of this - software, Stanford University requests that any recipient of it maintain - this notice affixed to any distribution by the recipient that contains a - copy or derivative of this software. - diff --git a/rtemsNfs-1.1/Makefile b/rtemsNfs-1.1/Makefile deleted file mode 100644 index a77b0f8..0000000 --- a/rtemsNfs-1.1/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# $Id$ -# - - -include $(RTEMS_MAKEFILE_PATH)/Makefile.inc - -include $(RTEMS_CUSTOM) -include $(RTEMS_ROOT)/make/directory.cfg - -SUBDIRS=proto src - -REVISION=$(filter-out $$%,$$Name$$) - -tar: tar-recursive - @$(make-tar) diff --git a/rtemsNfs-1.1/README b/rtemsNfs-1.1/README deleted file mode 100644 index 3291329..0000000 --- a/rtemsNfs-1.1/README +++ /dev/null @@ -1,491 +0,0 @@ -RTEMS-NFS -========= - -A NFS-V2 client implementation for the RTEMS real-time -executive. - -Author: Till Straumann , 2002 - -Copyright 2002, Stanford University and - Till Straumann - -Stanford Notice -*************** - -Acknowledgement of sponsorship -* * * * * * * * * * * * * * * * -This software was produced by the Stanford Linear Accelerator Center, -Stanford University, under Contract DE-AC03-76SFO0515 with the Department -of Energy. - - -Contents --------- -I Overview - 1) Performance - 2) Reference Platform / Test Environment - -II Usage - 1) Initialization - 2) Mounting Remote Server Filesystems - 3) Unmounting - 4) Unloading - 5) Dumping Information / Statistics - -III Implementation Details - 1) RPCIOD - 2) NFS - 3) RTEMS Resources Used By NFS/RPCIOD - 4) Caveats & Bugs - -IV Licensing & Disclaimers - -I Overview ------------ - -This package implements a simple non-caching NFS client -for RTEMS. Most of the system calls are supported -with the exception of 'mount', i.e. it is not possible -to mount another FS on top of NFS (mostly because -of the difficulty that arises when mount points are -deleted on the server). It shouldn't be hard to do, -though. - -Note: this client supports NFS vers. 2 / MOUNT vers. 1; - NFS Version 3 or higher are NOT supported. - -The package consists of two modules: RPCIOD and NFS itself. - - - RPCIOD is a UDP/RPC multiplexor daemon. It takes - RPC requests from multiple local client threads, - funnels them through a single socket to multiple - servers and dispatches the replies back to the - (blocked) requestor threads. - RPCIOD does packet retransmission and handles - timeouts etc. - Note however, that it does NOT do any XDR - marshalling - it is up to the requestor threads - to do the XDR encoding/decoding. RPCIOD _is_ RPC - specific, though, because its message dispatching - is based on the RPC transaction ID. - - - The NFS package maps RTEMS filesystem calls - to proper RPCs, it does the XDR work and - hands marshalled RPC requests to RPCIOD. - All of the calls are synchronous, i.e. they - block until they get a reply. - -1) Performance -- - - - - - - - -Performance sucks (due to the lack of readahead/delayed -write and caching). On a fast (100Mb/s) ethernet, it -takes about 20s to copy a 10MB file from NFS to NFS. -I found, however, that vxWorks' NFS client doesn't seem -to be any faster... - -2) Reference Platform -- - - - - - - - - - - -RTEMS-NFS was developed and tested on - - o RTEMS-ss20020301 (local patches applied) - o PowerPC G3, G4 on Synergy SVGM series board - (custom 'SVGM' BSP, to be released soon) - o PowerPC 604 on MVME23xx - (powerpc/shared/motorola-powerpc BSP) - o Test Environment: - - RTEMS executable running CEXP - - rpciod/nfs dynamically loaded from TFTPfs - - EPICS application dynamically loaded from NFS; - the executing IOC accesses all of its files - on NFS. - -II Usage ---------- - -After linking into the system and proper initialization -(rtems-NFS supports 'magic' module initialization when -loaded into a running system with the CEXP loader), -you are ready for mounting NFSes from a server -(I avoid the term NFS filesystem because NFS already -stands for 'Network File System'). - -You should also read the - - - "RTEMS Resources Used By NFS/RPCIOD" - - "CAVEATS & BUGS" - -below. - -1) Initialization -- - - - - - - - - -NFS consists of two modules who must be initialized: - - a) the RPCIO daemon package; by calling - - rpcUdpInit(); - - note that this step must be performed prior to - initializing NFS: - - b) NFS is initialized by calling - - nfsInit( smallPoolDepth, bigPoolDepth ); - - if you supply 0 (zero) values for the pool - depths, the compile-time default configuration - is used which should work fine. - -NOTE: when using CEXP to load these modules into a -running system, initialization will be performed -automagically. - -2) Mounting Remote Server Filesystems -- - - - - - - - - - - - - - - - - - - - -There are two interfaces for mounting an NFS: - - - The (non-POSIX) RTEMS 'mount()' call: - - mount( &mount_table_entry_pointer, - &filesystem_operations_table_pointer, - options, - device, - mount_point ) - - Note that you must specify a 'mount_table_entry_pointer' - (use a dummy) - RTEMS' mount() doesn't grok a NULL for - the first argument. - - o for the 'filesystem_operations_table_pointer', supply - - &nfs_fs_ops - - o options are constants (see RTEMS headers) for specifying - read-only / read-write mounts. - - o the 'device' string specifies the remote filesystem - who is to be mounted. NFS expects a string conforming - to the following format (EBNF syntax): - - [ '.' '@' ] ':' - - The first optional part of the string allows you - to specify the credentials to be used for all - subsequent transactions with this server. If the - string is omitted, the EUID/EGID of the executing - thread (i.e. the thread performing the 'mount' - - NFS will still 'remember' these values and use them - for all future communication with this server). - - The part denotes the server IP address - in standard 'dot' notation. It is followed by - a colon and the (absolute) path on the server. - Note that no extra characters or whitespace must - be present in the string. Example 'device' strings - are: - - "300.99@192.168.44.3:/remote/rtems/root" - - "192.168.44.3:/remote/rtems/root" - - o the 'mount_point' string identifies the local - directory (most probably on IMFS) where the NFS - is to be mounted. Note that the mount point must - already exist with proper permissions. - - - Alternate 'mount' interface. NFS offers a more - convenient wrapper taking three string arguments: - - nfsMount(uidgid_at_host, server_path, mount_point) - - This interface does DNS lookup (see reentrancy note - below) and creates the mount point if necessary. - - o the first argument specifies the server and - optionally the uid/gid to be used for authentication. - The semantics are exactly as described above: - - [ '.' '@' ] - - The part may be either a host _name_ or - an IP address in 'dot' notation. In the former - case, nfsMount() uses 'gethostbyname()' to do - a DNS lookup. - - IMPORTANT NOTE: gethostbyname() is NOT reentrant/ - thread-safe and 'nfsMount()' (if not provided with an - IP/dot address string) is hence subject to race conditions. - - o the 'server_path' and 'mount_point' arguments - are described above. - NOTE: If the mount point does not exist yet, - nfsMount() tries to create it. - - o if nfsMount() is called with a NULL 'uidgid_at_host' - argument, it lists all currently mounted NFS - -3) Unmounting -- - - - - - - -An NFS can be unmounted using RTEMS 'unmount()' -call (yep, it is unmount() - not umount()): - - unmount(mount_point) - -Note that you _must_ supply the mount point (string -argument). It is _not_ possible to specify the -'mountee' when unmounting. NFS implements no -convenience wrapper for this (yet), essentially because -(although this sounds unbelievable) it is non-trivial -to lookup the path leading to an RTEMS filesystem -directory node. - -4) Unloading -- - - - - - - -After unmounting all NFS from the system, the NFS -and RPCIOD modules may be stopped and unloaded. -Just call 'nfsCleanup()' and 'rpcUdpCleanup()' -in this order. You should evaluate the return value -of these routines which is non-zero if either -of them refuses to yield (e.g. because there are -still mounted filesystems). -Again, when unloading is done by CEXP this is -transparently handled. - -5) Dumping Information / Statistics -- - - - - - - - - - - - - - - - - - - -Rudimentary RPCIOD statistics are printed -to a file (stdout when NULL) by - - int rpcUdpStats(FILE *f) - -A list of all currently mounted NFS can be -printed to a file (stdout if NULL) using - - int nfsMountsShow(FILE *f) - -For convenience, this routine is also called -by nfsMount() when supplying NULL arguments. - -III Implementation Details --------------------------- - -1) RPCIOD -- - - - - - -RPCIOD was created to - -a) avoid non-reentrant librpc calls. -b) support 'asynchronous' operation over a single - socket. - -RPCIOD is a daemon thread handling 'transaction objects' -(XACTs) through an UDP socket. XACTs are marshalled RPC -calls/replies associated with RPC servers and requestor -threads. - -requestor thread: network: - - XACT packet - | | - V V - | message queue | ( socket ) - | | ^ - ----------> <----- | | - RPCIOD | - / -------------- - timeout/ (re) transmission - - -A requestor thread drops a transaction into -the message queue and goes to sleep. The XACT is -picked up by rpciod who is listening for events from -three sources: - - o the request queue - o packet arrival at the socket - o timeouts - -RPCIOD sends the XACT to its destination server and -enqueues the pending XACT into an ordered list of -outstanding transactions. - -When a packet arrives, RPCIOD (based on the RPC transaction -ID) looks up the matching XACT and wakes up the requestor -who can then XDR-decode the RPC results found in the XACT -object's buffer. - -When a timeout expires, RPCIOD examines the outstanding -XACT that is responsible for the timeout. If its lifetime -has not expired yet, RPCIOD resends the request. Otherwise, -the XACT's error status is set and the requestor is woken up. - -RPCIOD dynamically adjusts the retransmission intervals -based on the average round-trip time measured (on a per-server -basis). - -Having the requestors event driven (rather than blocking -e.g. on a semaphore) is geared to having many different -requestors (one synchronization object per requestor would -be needed otherwise). - -Requestors who want to do asynchronous IO need a different -interface which will be added in the future. - -1.a) Reentrancy -- - - - - - - - -RPCIOD does no non-reentrant librpc calls. - -1.b) Efficiency -- - - - - - - - -We shouldn't bother about efficiency until pipelining (read-ahead/ -delayed write) and caching are implemented. The round-trip delay -associated with every single RPC transaction clearly is a big -performance killer. - -Nevertheless, I could not withstand the temptation to eliminate -the extra copy step involved with socket IO: - -A user data object has to be XDR encoded into a buffer. The -buffer given to the socket where it is copied into MBUFs. -(The network chip driver might even do more copying). - -Likewise, on reception 'recvfrom' copies MBUFS into a user -buffer which is XDR decoded into the final user data object. - -Eliminating the copying into (possibly multiple) MBUFS by -'sendto()' is actually a piece of cake. RPCIOD uses the -'sosend()' routine [properly wrapped] supplying a single -MBUF header who directly points to the marshalled buffer -:-) - -Getting rid of the extra copy on reception was (only a little) -harder: I derived a 'XDR-mbuf' stream from SUN's xdr_mem which -allows for XDR-decoding out of a MBUF chain who is obtained by -soreceive(). - -2) NFS -- - - - -The actual NFS implementation is straightforward and essentially -'passive' (no threads created). Any RTEMS task executing a -filesystem call dispatched to NFS (such as 'opendir()', 'lseek()' -or 'unlink()') ends up XDR encoding arguments, dropping a -XACT into RPCIOD's message queue and going to sleep. -When woken up by RPCIOD, the XACT is decoded (using the XDR-mbuf -stream mentioned above) and the properly cooked-up results are -returned. - -3) RTEMS Resources Used By NFS/RPCIOD -- - - - - - - - - - - - - - - - - - - - -The RPCIOD/NFS package uses the following resources. Some -parameters are compile-time configurable - consult the -source files for details. - -RPCIOD: - o 1 task - o 1 message queue - o 1 socket/filedescriptor - o 2 semaphores (a third one is temporarily created during - rpcUdpCleanup()). - o 1 RTEMS EVENT (by default RTEMS_EVENT_30). - IMPORTANT: this event is used by _every_ thread executing - NFS system calls and hence is RESERVED. - o 3 events only used by RPCIOD itself, i.e. these must not - be sent to RPCIOD by no other thread (except for the intended - use, of course). The events involved are 1,2,3. - o preemption disabled sections: NONE - o sections with interrupts disabled: NONE - o NO 'timers' are used (timer code would run in IRQ context) - o memory usage: n.a - -NFS: - o 2 message queues - o 2 semaphores - o 1 semaphore per mounted NFS - o 1 slot in driver entry table (for major number) - o preemption disabled sections: NONE - o sections with interrupts disabled: NONE - o 1 task + 1 semaphore temporarily created when - listing mounted filesystems (rtems_filesystem_resolve_location()) - -4) CAVEATS & BUGS -- - - - - - - - - -Unfortunately, some bugs crawl around in the filesystem generics. -(Some of them might already be fixed in versions later than -rtems-ss-20020301). -I recommend to use the patch distributed with RTEMS-NFS. - - o RTEMS uses/used (Joel said it has been fixed already) a 'short' - ino_t which is not enough for NFS. - The driver detects this problem and enables a workaround. In rare - situations (mainly involving 'getcwd()' improper inode comparison - may result (due to the restricted size, stat() returns st_ino modulo - 2^16). In most cases, however, st_dev is compared along with st_ino - which will give correct results (different files may yield identical - st_ino but they will have different st_dev). However, there is - code (in getcwd(), for example) who assumes that files residing - in one directory must be hosted by the same device and hence omits - the st_dev comparison. In such a case, the workaround will fail. - - NOTE: changing the size (sys/types.h) of ino_t from 'short' to 'long' - is strongly recommended. It is NOT included in the patch, however - as this is a major change requiring ALL of your sources to - be recompiled. - - THE ino_t SIZE IS FIXED IN GCC-3.2/NEWLIB-1.10.0-2 DISTRIBUTED BY - OAR. - - o You may work around most filesystem bugs by observing the following - rules: - - * never use chroot() (fixed by the patch) - * never use getpwent(), getgrent() & friends - they are NOT THREAD - safe (fixed by the patch) - * NEVER use rtems_libio_share_private_env() - not even with the - patch applied. Just DONT - it is broken by design. - * All threads who have their own userenv (who have called - rtems_libio_set_private_env()) SHOULD 'chdir("/")' before - terminating. Otherwise, (i.e. if their cwd is on NFS), it will - be impossible to unmount the NFS involved. - - o The patch slightly changes the semantics of 'getpwent()' and - 'getgrent()' & friends (to what is IMHO correct anyways - the patch is - also needed to fix another problem, however): with the patch applied, - the passwd and group files are always accessed from the 'current' user - environment, i.e. a thread who has changed its 'root' or 'uid' might - not be able to access these files anymore. - - o NOTE: RTEMS 'mount()' / 'unmount()' are NOT THREAD SAFE. - -IV Licensing & Disclaimers --------------------------- - -NFS is distributed under the EPICS Open License - consult the -separate 'LICENSE' file. - -Government disclaimer of liability -- - - - - - - - - - - - - - - - - -Neither the United States nor the United States Department of Energy, -nor any of their employees, makes any warranty, express or implied, -or assumes any legal liability or responsibility for the accuracy, -completeness, or usefulness of any data, apparatus, product, or process -disclosed, or represents that its use would not infringe privately -owned rights. - -Stanford disclaimer of liability -- - - - - - - - - - - - - - - - - -Stanford University makes no representations or warranties, express or -implied, nor assumes any liability for the use of this software. - -This product is subject to the EPICS open license -- - - - - - - - - - - - - - - - - - - - - - - - - -Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php -for more information. - -Maintenance of notice -- - - - - - - - - - - -In the interest of clarity regarding the origin and status of this -software, Stanford University requests that any recipient of it maintain -this notice affixed to any distribution by the recipient that contains a -copy or derivative of this software. diff --git a/rtemsNfs-1.1/proto/Makefile b/rtemsNfs-1.1/proto/Makefile deleted file mode 100644 index 57a9830..0000000 --- a/rtemsNfs-1.1/proto/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# -# $Id$ -# -# Templates/Makefile.lib -# Template library Makefile -# - - -LIBNAME=libnfsprot.a # xxx- your library names goes here -LIB=${ARCH}/${LIBNAME} - -# C and C++ source names, if any, go here -- minus the .c or .cc -C_PIECES=nfs_prot_xdr mount_prot_xdr -C_FILES=$(C_PIECES:%=%.c) -C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) - -CC_PIECES= -CC_FILES=$(CC_PIECES:%=%.cc) -CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o) - -H_FILES= - -XFILES = $(wildcard *.x) - -# Assembly source names, if any, go here -- minus the .S -S_PIECES= -S_FILES=$(S_PIECES:%=%.S) -S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o) - -SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) -OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES) - -include $(RTEMS_MAKEFILE_PATH)/Makefile.inc - -include $(RTEMS_CUSTOM) -include $(RTEMS_ROOT)/make/lib.cfg - -# -# Add local stuff here using += -# - -DEFINES += -CPPFLAGS += -# inline declarations require -O -CFLAGS += -O2 -Winline - -# -# Add your list of files to delete here. The config files -# already know how to delete some stuff, so you may want -# to just run 'make clean' first to see what gets missed. -# 'make clobber' already includes 'make clean' -# - -CLEAN_ADDITIONS += -CLOBBER_ADDITIONS += $(XFILES:%.x=%*.c) $(XFILES:%.x=%*.h) - -all: ${ARCH} $(SRCS) $(LIB) - -$(LIB): ${OBJS} - $(make-library) - -%_xdr.c: %.x %.h - rpcgen -c $< > $@ - -%.h: %.x - rpcgen -h $< > $@ - -.PRECIOUS: $(XFILES:%.x=%.h) $(XFILES:%.x=%_xdr.c) - -tar: $(XFILES:%.x=%.h) $(XFILES:%.x=%_xdr.c) - -distclean: clean - -# DONT install this library. -install: all diff --git a/rtemsNfs-1.1/proto/mount_prot.x b/rtemsNfs-1.1/proto/mount_prot.x deleted file mode 100644 index 444e998..0000000 --- a/rtemsNfs-1.1/proto/mount_prot.x +++ /dev/null @@ -1,161 +0,0 @@ -/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */ -/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/* - * Protocol description for the mount program - */ - - -const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ -const MNTNAMLEN = 255; /* maximum bytes in a name argument */ -const FHSIZE = 32; /* size in bytes of a file handle */ - -/* - * The fhandle is the file handle that the server passes to the client. - * All file operations are done using the file handles to refer to a file - * or a directory. The file handle can contain whatever information the - * server needs to distinguish an individual file. - */ -typedef opaque fhandle[FHSIZE]; - -/* - * If a status of zero is returned, the call completed successfully, and - * a file handle for the directory follows. A non-zero status indicates - * some sort of error. The status corresponds with UNIX error numbers. - */ -union fhstatus switch (unsigned fhs_status) { -case 0: - fhandle fhs_fhandle; -default: - void; -}; - -/* - * The type dirpath is the pathname of a directory - */ -typedef string dirpath; - -/* - * The type name is used for arbitrary names (hostnames, groupnames) - */ -typedef string name; - -/* - * A list of who has what mounted - */ -typedef struct mountbody *mountlist; -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; - -/* - * A list of netgroups - */ -typedef struct groupnode *groups; -struct groupnode { - name gr_name; - groups gr_next; -}; - -/* - * A list of what is exported and to whom - */ -typedef struct exportnode *exports; -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; - -program MOUNTPROG { - /* - * Version one of the mount protocol communicates with version two - * of the NFS protocol. The only connecting point is the fhandle - * structure, which is the same for both protocols. - */ - version MOUNTVERS { - /* - * Does no work. It is made available in all RPC services - * to allow server reponse testing and timing - */ - void - MOUNTPROC_NULL(void) = 0; - - /* - * If fhs_status is 0, then fhs_fhandle contains the - * file handle for the directory. This file handle may - * be used in the NFS protocol. This procedure also adds - * a new entry to the mount list for this client mounting - * the directory. - * Unix authentication required. - */ - fhstatus - MOUNTPROC_MNT(dirpath) = 1; - - /* - * Returns the list of remotely mounted filesystems. The - * mountlist contains one entry for each hostname and - * directory pair. - */ - mountlist - MOUNTPROC_DUMP(void) = 2; - - /* - * Removes the mount list entry for the directory - * Unix authentication required. - */ - void - MOUNTPROC_UMNT(dirpath) = 3; - - /* - * Removes all of the mount list entries for this client - * Unix authentication required. - */ - void - MOUNTPROC_UMNTALL(void) = 4; - - /* - * Returns a list of all the exported filesystems, and which - * machines are allowed to import it. - */ - exports - MOUNTPROC_EXPORT(void) = 5; - - /* - * Identical to MOUNTPROC_EXPORT above - */ - exports - MOUNTPROC_EXPORTALL(void) = 6; - } = 1; -} = 100005; diff --git a/rtemsNfs-1.1/proto/nfs_prot.x b/rtemsNfs-1.1/proto/nfs_prot.x deleted file mode 100644 index a40d9a5..0000000 --- a/rtemsNfs-1.1/proto/nfs_prot.x +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#ifndef RPC_HDR -%#ifndef lint -%/*static char sccsid[] = "from: @(#)nfs_prot.x 1.2 87/10/12 Copyr 1987 Sun Micro";*/ -%/*static char sccsid[] = "from: @(#)nfs_prot.x 2.1 88/08/01 4.0 RPCSRC";*/ -%static char rcsid[] = "$Id$"; -%#endif /* not lint */ -#endif - -const NFS_PORT = 2049; -const NFS_MAXDATA = 8192; -const NFS_MAXPATHLEN = 1024; -const NFS_MAXNAMLEN = 255; -const NFS_FHSIZE = 32; -const NFS_COOKIESIZE = 4; -const NFS_FIFO_DEV = -1; /* size kludge for named pipes */ - -/* - * File types - */ -const NFSMODE_FMT = 0170000; /* type of file */ -const NFSMODE_DIR = 0040000; /* directory */ -const NFSMODE_CHR = 0020000; /* character special */ -const NFSMODE_BLK = 0060000; /* block special */ -const NFSMODE_REG = 0100000; /* regular */ -const NFSMODE_LNK = 0120000; /* symbolic link */ -const NFSMODE_SOCK = 0140000; /* socket */ -const NFSMODE_FIFO = 0010000; /* fifo */ - -/* - * Error status - */ -enum nfsstat { - NFS_OK= 0, /* no error */ - NFSERR_PERM=1, /* Not owner */ - NFSERR_NOENT=2, /* No such file or directory */ - NFSERR_IO=5, /* I/O error */ - NFSERR_NXIO=6, /* No such device or address */ - NFSERR_ACCES=13, /* Permission denied */ - NFSERR_EXIST=17, /* File exists */ - NFSERR_NODEV=19, /* No such device */ - NFSERR_NOTDIR=20, /* Not a directory*/ - NFSERR_ISDIR=21, /* Is a directory */ - NFSERR_FBIG=27, /* File too large */ - NFSERR_NOSPC=28, /* No space left on device */ - NFSERR_ROFS=30, /* Read-only file system */ - NFSERR_NAMETOOLONG=63, /* File name too long */ - NFSERR_NOTEMPTY=66, /* Directory not empty */ - NFSERR_DQUOT=69, /* Disc quota exceeded */ - NFSERR_STALE=70, /* Stale NFS file handle */ - NFSERR_WFLUSH=99 /* write cache flushed */ -}; - -/* - * File types - */ -enum ftype { - NFNON = 0, /* non-file */ - NFREG = 1, /* regular file */ - NFDIR = 2, /* directory */ - NFBLK = 3, /* block special */ - NFCHR = 4, /* character special */ - NFLNK = 5, /* symbolic link */ - NFSOCK = 6, /* unix domain sockets */ - NFBAD = 7, /* unused */ - NFFIFO = 8 /* named pipe */ -}; - -/* - * File access handle - */ -struct nfs_fh { - opaque data[NFS_FHSIZE]; -}; - -/* - * Timeval - */ -struct nfstime { - unsigned seconds; - unsigned useconds; -}; - - -/* - * File attributes - */ -struct fattr { - ftype type; /* file type */ - unsigned mode; /* protection mode bits */ - unsigned nlink; /* # hard links */ - unsigned uid; /* owner user id */ - unsigned gid; /* owner group id */ - unsigned size; /* file size in bytes */ - unsigned blocksize; /* prefered block size */ - unsigned rdev; /* special device # */ - unsigned blocks; /* Kb of disk used by file */ - unsigned fsid; /* device # */ - unsigned fileid; /* inode # */ - nfstime atime; /* time of last access */ - nfstime mtime; /* time of last modification */ - nfstime ctime; /* time of last change */ -}; - -/* - * File attributes which can be set - */ -struct sattr { - unsigned mode; /* protection mode bits */ - unsigned uid; /* owner user id */ - unsigned gid; /* owner group id */ - unsigned size; /* file size in bytes */ - nfstime atime; /* time of last access */ - nfstime mtime; /* time of last modification */ -}; - - -typedef string filename; -typedef string nfspath; - -/* - * Reply status with file attributes - */ -union attrstat switch (nfsstat status) { -case NFS_OK: - fattr attributes; -default: - void; -}; - -struct sattrargs { - nfs_fh file; - sattr attributes; -}; - -/* - * Arguments for directory operations - */ -struct diropargs { - nfs_fh dir; /* directory file handle */ - filename name; /* name (up to NFS_MAXNAMLEN bytes) */ -}; - -struct diropokres { - nfs_fh file; - fattr attributes; -}; - -/* - * Results from directory operation - */ -union diropres switch (nfsstat status) { -case NFS_OK: - diropokres diropres; -default: - void; -}; - -union readlinkres switch (nfsstat status) { -case NFS_OK: - nfspath data; -default: - void; -}; - -/* - * Arguments to remote read - */ -struct readargs { - nfs_fh file; /* handle for file */ - unsigned offset; /* byte offset in file */ - unsigned count; /* immediate read count */ - unsigned totalcount; /* total read count (from this offset)*/ -}; - -/* - * Status OK portion of remote read reply - */ -struct readokres { - fattr attributes; /* attributes, need for pagin*/ - opaque data; -}; - -union readres switch (nfsstat status) { -case NFS_OK: - readokres reply; -default: - void; -}; - -/* - * Arguments to remote write - */ -struct writeargs { - nfs_fh file; /* handle for file */ - unsigned beginoffset; /* beginning byte offset in file */ - unsigned offset; /* current byte offset in file */ - unsigned totalcount; /* total write count (to this offset)*/ - opaque data; -}; - -struct createargs { - diropargs where; - sattr attributes; -}; - -struct renameargs { - diropargs from; - diropargs to; -}; - -struct linkargs { - nfs_fh from; - diropargs to; -}; - -struct symlinkargs { - diropargs from; - nfspath to; - sattr attributes; -}; - - -/* TS, 10/21/2002; converted cookie to struct */ -struct nfscookie { - opaque data[NFS_COOKIESIZE]; -}; - -/* - * Arguments to readdir - */ -struct readdirargs { - nfs_fh dir; /* directory handle */ - nfscookie cookie; - unsigned count; /* number of directory bytes to read */ -}; - -struct entry { - unsigned fileid; - filename name; - nfscookie cookie; - entry *nextentry; -}; - -struct dirlist { - entry *entries; - bool eof; -}; - -union readdirres switch (nfsstat status) { -case NFS_OK: - dirlist reply; -default: - void; -}; - -struct statfsokres { - unsigned tsize; /* preferred transfer size in bytes */ - unsigned bsize; /* fundamental file system block size */ - unsigned blocks; /* total blocks in file system */ - unsigned bfree; /* free blocks in fs */ - unsigned bavail; /* free blocks avail to non-superuser */ -}; - -union statfsres switch (nfsstat status) { -case NFS_OK: - statfsokres reply; -default: - void; -}; - -#ifdef WANT_NFS3 - -/* - * NFSv3 constants and types - */ -const NFS3_FHSIZE = 64; /* maximum size in bytes of a file handle */ -const NFS3_COOKIEVERFSIZE = 8; /* size of a cookie verifier for READDIR */ -const NFS3_CREATEVERFSIZE = 8; /* size of the verifier used for CREATE */ -const NFS3_WRITEVERFSIZE = 8; /* size of the verifier used for WRITE */ - -typedef unsigned hyper uint64; -typedef hyper int64; -typedef unsigned long uint32; -typedef long int32; -typedef string filename3<>; -typedef string nfspath3<>; -typedef uint64 fileid3; -typedef uint64 cookie3; -typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; -typedef opaque createverf3[NFS3_CREATEVERFSIZE]; -typedef opaque writeverf3[NFS3_WRITEVERFSIZE]; -typedef uint32 uid3; -typedef uint32 gid3; -typedef uint64 size3; -typedef uint64 offset3; -typedef uint32 mode3; -typedef uint32 count3; - -/* - * Error status (v3) - */ -enum nfsstat3 { - NFS3_OK = 0, - NFS3ERR_PERM = 1, - NFS3ERR_NOENT = 2, - NFS3ERR_IO = 5, - NFS3ERR_NXIO = 6, - NFS3ERR_ACCES = 13, - NFS3ERR_EXIST = 17, - NFS3ERR_XDEV = 18, - NFS3ERR_NODEV = 19, - NFS3ERR_NOTDIR = 20, - NFS3ERR_ISDIR = 21, - NFS3ERR_INVAL = 22, - NFS3ERR_FBIG = 27, - NFS3ERR_NOSPC = 28, - NFS3ERR_ROFS = 30, - NFS3ERR_MLINK = 31, - NFS3ERR_NAMETOOLONG = 63, - NFS3ERR_NOTEMPTY = 66, - NFS3ERR_DQUOT = 69, - NFS3ERR_STALE = 70, - NFS3ERR_REMOTE = 71, - NFS3ERR_BADHANDLE = 10001, - NFS3ERR_NOT_SYNC = 10002, - NFS3ERR_BAD_COOKIE = 10003, - NFS3ERR_NOTSUPP = 10004, - NFS3ERR_TOOSMALL = 10005, - NFS3ERR_SERVERFAULT = 10006, - NFS3ERR_BADTYPE = 10007, - NFS3ERR_JUKEBOX = 10008 -}; - -/* - * File types (v3) - */ -enum ftype3 { - NF3REG = 1, /* regular file */ - NF3DIR = 2, /* directory */ - NF3BLK = 3, /* block special */ - NF3CHR = 4, /* character special */ - NF3LNK = 5, /* symbolic link */ - NF3SOCK = 6, /* unix domain sockets */ - NF3FIFO = 7 /* named pipe */ -}; - -struct specdata3 { - uint32 specdata1; - uint32 specdata2; -}; - -/* - * File access handle (v3) - */ -struct nfs_fh3 { - opaque data; -}; - -/* - * Timeval (v3) - */ -struct nfstime3 { - uint32 seconds; - uint32 nseconds; -}; - - -/* - * File attributes (v3) - */ -struct fattr3 { - ftype3 type; /* file type */ - mode3 mode; /* protection mode bits */ - uint32 nlink; /* # hard links */ - uid3 uid; /* owner user id */ - gid3 gid; /* owner group id */ - size3 size; /* file size in bytes */ - size3 used; /* prefered block size */ - specdata3 rdev; /* special device # */ - uint64 fsid; /* device # */ - fileid3 fileid; /* inode # */ - nfstime3 atime; /* time of last access */ - nfstime3 mtime; /* time of last modification */ - nfstime3 ctime; /* time of last change */ -}; - -union post_op_attr switch (bool attributes_follow) { -case TRUE: - fattr3 attributes; -case FALSE: - void; -}; - -struct wcc_attr { - size3 size; - nfstime3 mtime; - nfstime3 ctime; -}; - -union pre_op_attr switch (bool attributes_follow) { -case TRUE: - wcc_attr attributes; -case FALSE: - void; -}; - -struct wcc_data { - pre_op_attr before; - post_op_attr after; -}; - -union post_op_fh3 switch (bool handle_follows) { -case TRUE: - nfs_fh3 handle; -case FALSE: - void; -}; - -/* - * File attributes which can be set (v3) - */ -enum time_how { - DONT_CHANGE = 0, - SET_TO_SERVER_TIME = 1, - SET_TO_CLIENT_TIME = 2 -}; - -union set_mode3 switch (bool set_it) { -case TRUE: - mode3 mode; -default: - void; -}; - -union set_uid3 switch (bool set_it) { -case TRUE: - uid3 uid; -default: - void; -}; - -union set_gid3 switch (bool set_it) { -case TRUE: - gid3 gid; -default: - void; -}; - -union set_size3 switch (bool set_it) { -case TRUE: - size3 size; -default: - void; -}; - -union set_atime switch (time_how set_it) { -case SET_TO_CLIENT_TIME: - nfstime3 atime; -default: - void; -}; - -union set_mtime switch (time_how set_it) { -case SET_TO_CLIENT_TIME: - nfstime3 mtime; -default: - void; -}; - -struct sattr3 { - set_mode3 mode; - set_uid3 uid; - set_gid3 gid; - set_size3 size; - set_atime atime; - set_mtime mtime; -}; - -/* - * Arguments for directory operations (v3) - */ -struct diropargs3 { - nfs_fh3 dir; /* directory file handle */ - filename3 name; /* name (up to NFS_MAXNAMLEN bytes) */ -}; - -/* - * Arguments to getattr (v3). - */ -struct GETATTR3args { - nfs_fh3 object; -}; - -struct GETATTR3resok { - fattr3 obj_attributes; -}; - -union GETATTR3res switch (nfsstat3 status) { -case NFS3_OK: - GETATTR3resok resok; -default: - void; -}; - -/* - * Arguments to setattr (v3). - */ -union sattrguard3 switch (bool check) { -case TRUE: - nfstime3 obj_ctime; -case FALSE: - void; -}; - -struct SETATTR3args { - nfs_fh3 object; - sattr3 new_attributes; - sattrguard3 guard; -}; - -struct SETATTR3resok { - wcc_data obj_wcc; -}; - -struct SETATTR3resfail { - wcc_data obj_wcc; -}; - -union SETATTR3res switch (nfsstat3 status) { -case NFS3_OK: - SETATTR3resok resok; -default: - SETATTR3resfail resfail; -}; - -/* - * Arguments to lookup (v3). - */ -struct LOOKUP3args { - diropargs3 what; -}; - -struct LOOKUP3resok { - nfs_fh3 object; - post_op_attr obj_attributes; - post_op_attr dir_attributes; -}; - -struct LOOKUP3resfail { - post_op_attr dir_attributes; -}; - -union LOOKUP3res switch (nfsstat3 status) { -case NFS3_OK: - LOOKUP3resok resok; -default: - LOOKUP3resfail resfail; -}; - -/* - * Arguments to access (v3). - */ -const ACCESS3_READ = 0x0001; -const ACCESS3_LOOKUP = 0x0002; -const ACCESS3_MODIFY = 0x0004; -const ACCESS3_EXTEND = 0x0008; -const ACCESS3_DELETE = 0x0010; -const ACCESS3_EXECUTE = 0x0020; - -struct ACCESS3args { - nfs_fh3 object; - uint32 access; -}; - -struct ACCESS3resok { - post_op_attr obj_attributes; - uint32 access; -}; - -struct ACCESS3resfail { - post_op_attr obj_attributes; -}; - -union ACCESS3res switch (nfsstat3 status) { -case NFS3_OK: - ACCESS3resok resok; -default: - ACCESS3resfail resfail; -}; - -/* - * Arguments to readlink (v3). - */ -struct READLINK3args { - nfs_fh3 symlink; -}; - -struct READLINK3resok { - post_op_attr symlink_attributes; - nfspath3 data; -}; - -struct READLINK3resfail { - post_op_attr symlink_attributes; -}; - -union READLINK3res switch (nfsstat3 status) { -case NFS3_OK: - READLINK3resok resok; -default: - READLINK3resfail resfail; -}; - -/* - * Arguments to read (v3). - */ -struct READ3args { - nfs_fh3 file; - offset3 offset; - count3 count; -}; - -struct READ3resok { - post_op_attr file_attributes; - count3 count; - bool eof; - opaque data<>; -}; - -struct READ3resfail { - post_op_attr file_attributes; -}; - -/* XXX: solaris 2.6 uses ``nfsstat'' here */ -union READ3res switch (nfsstat3 status) { -case NFS3_OK: - READ3resok resok; -default: - READ3resfail resfail; -}; - -/* - * Arguments to write (v3). - */ -enum stable_how { - UNSTABLE = 0, - DATA_SYNC = 1, - FILE_SYNC = 2 -}; - -struct WRITE3args { - nfs_fh3 file; - offset3 offset; - count3 count; - stable_how stable; - opaque data<>; -}; - -struct WRITE3resok { - wcc_data file_wcc; - count3 count; - stable_how committed; - writeverf3 verf; -}; - -struct WRITE3resfail { - wcc_data file_wcc; -}; - -union WRITE3res switch (nfsstat3 status) { -case NFS3_OK: - WRITE3resok resok; -default: - WRITE3resfail resfail; -}; - -/* - * Arguments to create (v3). - */ -enum createmode3 { - UNCHECKED = 0, - GUARDED = 1, - EXCLUSIVE = 2 -}; - -union createhow3 switch (createmode3 mode) { -case UNCHECKED: -case GUARDED: - sattr3 obj_attributes; -case EXCLUSIVE: - createverf3 verf; -}; - -struct CREATE3args { - diropargs3 where; - createhow3 how; -}; - -struct CREATE3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; - -struct CREATE3resfail { - wcc_data dir_wcc; -}; - -union CREATE3res switch (nfsstat3 status) { -case NFS3_OK: - CREATE3resok resok; -default: - CREATE3resfail resfail; -}; - -/* - * Arguments to mkdir (v3). - */ -struct MKDIR3args { - diropargs3 where; - sattr3 attributes; -}; - -struct MKDIR3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; - -struct MKDIR3resfail { - wcc_data dir_wcc; -}; - -union MKDIR3res switch (nfsstat3 status) { -case NFS3_OK: - MKDIR3resok resok; -default: - MKDIR3resfail resfail; -}; - -/* - * Arguments to symlink (v3). - */ -struct symlinkdata3 { - sattr3 symlink_attributes; - nfspath3 symlink_data; -}; - -struct SYMLINK3args { - diropargs3 where; - symlinkdata3 symlink; -}; - -struct SYMLINK3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; - -struct SYMLINK3resfail { - wcc_data dir_wcc; -}; - -union SYMLINK3res switch (nfsstat3 status) { -case NFS3_OK: - SYMLINK3resok resok; -default: - SYMLINK3resfail resfail; -}; - -/* - * Arguments to mknod (v3). - */ -struct devicedata3 { - sattr3 dev_attributes; - specdata3 spec; -}; - -union mknoddata3 switch (ftype3 type) { -case NF3CHR: -case NF3BLK: - devicedata3 device; -case NF3SOCK: -case NF3FIFO: - sattr3 pipe_attributes; -default: - void; -}; - -struct MKNOD3args { - diropargs3 where; - mknoddata3 what; -}; - -struct MKNOD3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; - -struct MKNOD3resfail { - wcc_data dir_wcc; -}; - -union MKNOD3res switch (nfsstat3 status) { -case NFS3_OK: - MKNOD3resok resok; -default: - MKNOD3resfail resfail; -}; - -/* - * Arguments to remove (v3). - */ -struct REMOVE3args { - diropargs3 object; -}; - -struct REMOVE3resok { - wcc_data dir_wcc; -}; - -struct REMOVE3resfail { - wcc_data dir_wcc; -}; - -union REMOVE3res switch (nfsstat3 status) { -case NFS3_OK: - REMOVE3resok resok; -default: - REMOVE3resfail resfail; -}; - -/* - * Arguments to rmdir (v3). - */ -struct RMDIR3args { - diropargs3 object; -}; - -struct RMDIR3resok { - wcc_data dir_wcc; -}; - -struct RMDIR3resfail { - wcc_data dir_wcc; -}; - -union RMDIR3res switch (nfsstat3 status) { -case NFS3_OK: - RMDIR3resok resok; -default: - RMDIR3resfail resfail; -}; - -/* - * Arguments to rename (v3). - */ -struct RENAME3args { - diropargs3 from; - diropargs3 to; -}; - -struct RENAME3resok { - wcc_data fromdir_wcc; - wcc_data todir_wcc; -}; - -struct RENAME3resfail { - wcc_data fromdir_wcc; - wcc_data todir_wcc; -}; - -union RENAME3res switch (nfsstat3 status) { -case NFS3_OK: - RENAME3resok resok; -default: - RENAME3resfail resfail; -}; - -/* - * Arguments to link (v3). - */ -struct LINK3args { - nfs_fh3 file; - diropargs3 link; -}; - -struct LINK3resok { - post_op_attr file_attributes; - wcc_data linkdir_wcc; -}; - -struct LINK3resfail { - post_op_attr file_attributes; - wcc_data linkdir_wcc; -}; - -union LINK3res switch (nfsstat3 status) { -case NFS3_OK: - LINK3resok resok; -default: - LINK3resfail resfail; -}; - -/* - * Arguments to readdir (v3). - */ -struct READDIR3args { - nfs_fh3 dir; - cookie3 cookie; - cookieverf3 cookieverf; - count3 count; -}; - -struct entry3 { - fileid3 fileid; - filename3 name; - cookie3 cookie; - entry3 *nextentry; -}; - -struct dirlist3 { - entry3 *entries; - bool eof; -}; - -struct READDIR3resok { - post_op_attr dir_attributes; - cookieverf3 cookieverf; - dirlist3 reply; -}; - -struct READDIR3resfail { - post_op_attr dir_attributes; -}; - -union READDIR3res switch (nfsstat3 status) { -case NFS3_OK: - READDIR3resok resok; -default: - READDIR3resfail resfail; -}; - -/* - * Arguments to readdirplus (v3). - */ -struct READDIRPLUS3args { - nfs_fh3 dir; - cookie3 cookie; - cookieverf3 cookieverf; - count3 dircount; - count3 maxcount; -}; - -struct entryplus3 { - fileid3 fileid; - filename3 name; - cookie3 cookie; - post_op_attr name_attributes; - post_op_fh3 name_handle; - entryplus3 *nextentry; -}; - -struct dirlistplus3 { - entryplus3 *entries; - bool eof; -}; - -struct READDIRPLUS3resok { - post_op_attr dir_attributes; - cookieverf3 cookieverf; - dirlistplus3 reply; -}; - -struct READDIRPLUS3resfail { - post_op_attr dir_attributes; -}; - -union READDIRPLUS3res switch (nfsstat3 status) { -case NFS3_OK: - READDIRPLUS3resok resok; -default: - READDIRPLUS3resfail resfail; -}; - -/* - * Arguments to fsstat (v3). - */ -struct FSSTAT3args { - nfs_fh3 fsroot; -}; - -struct FSSTAT3resok { - post_op_attr obj_attributes; - size3 tbytes; - size3 fbytes; - size3 abytes; - size3 tfiles; - size3 ffiles; - size3 afiles; - uint32 invarsec; -}; - -struct FSSTAT3resfail { - post_op_attr obj_attributes; -}; - -union FSSTAT3res switch (nfsstat3 status) { -case NFS3_OK: - FSSTAT3resok resok; -default: - FSSTAT3resfail resfail; -}; - -/* - * Arguments to fsinfo (v3). - */ -const FSF3_LINK = 0x0001; -const FSF3_SYMLINK = 0x0002; -const FSF3_HOMOGENEOUS = 0x0008; -const FSF3_CANSETTIME = 0x0010; - -struct FSINFO3args { - nfs_fh3 fsroot; -}; - -struct FSINFO3resok { - post_op_attr obj_attributes; - uint32 rtmax; - uint32 rtpref; - uint32 rtmult; - uint32 wtmax; - uint32 wtpref; - uint32 wtmult; - uint32 dtpref; - size3 maxfilesize; - nfstime3 time_delta; - uint32 properties; -}; - -struct FSINFO3resfail { - post_op_attr obj_attributes; -}; - -union FSINFO3res switch (nfsstat3 status) { -case NFS3_OK: - FSINFO3resok resok; -default: - FSINFO3resfail resfail; -}; - -/* - * Arguments to pathconf (v3). - */ -struct PATHCONF3args { - nfs_fh3 object; -}; - -struct PATHCONF3resok { - post_op_attr obj_attributes; - uint32 linkmax; - uint32 name_max; - bool no_trunc; - bool chown_restricted; - bool case_insensitive; - bool case_preserving; -}; - -struct PATHCONF3resfail { - post_op_attr obj_attributes; -}; - -union PATHCONF3res switch (nfsstat3 status) { -case NFS3_OK: - PATHCONF3resok resok; -default: - PATHCONF3resfail resfail; -}; - -/* - * Arguments to commit (v3). - */ -struct COMMIT3args { - nfs_fh3 file; - offset3 offset; - count3 count; -}; - -struct COMMIT3resok { - wcc_data file_wcc; - writeverf3 verf; -}; - -struct COMMIT3resfail { - wcc_data file_wcc; -}; - -union COMMIT3res switch (nfsstat3 status) { -case NFS3_OK: - COMMIT3resok resok; -default: - COMMIT3resfail resfail; -}; - -#endif /* WANT_NFS3 */ - -/* - * Remote file service routines - */ -program NFS_PROGRAM { - version NFS_VERSION { - void - NFSPROC_NULL(void) = 0; - - attrstat - NFSPROC_GETATTR(nfs_fh) = 1; - - attrstat - NFSPROC_SETATTR(sattrargs) = 2; - - void - NFSPROC_ROOT(void) = 3; - - diropres - NFSPROC_LOOKUP(diropargs) = 4; - - readlinkres - NFSPROC_READLINK(nfs_fh) = 5; - - readres - NFSPROC_READ(readargs) = 6; - - void - NFSPROC_WRITECACHE(void) = 7; - - attrstat - NFSPROC_WRITE(writeargs) = 8; - - diropres - NFSPROC_CREATE(createargs) = 9; - - nfsstat - NFSPROC_REMOVE(diropargs) = 10; - - nfsstat - NFSPROC_RENAME(renameargs) = 11; - - nfsstat - NFSPROC_LINK(linkargs) = 12; - - nfsstat - NFSPROC_SYMLINK(symlinkargs) = 13; - - diropres - NFSPROC_MKDIR(createargs) = 14; - - nfsstat - NFSPROC_RMDIR(diropargs) = 15; - - readdirres - NFSPROC_READDIR(readdirargs) = 16; - - statfsres - NFSPROC_STATFS(nfs_fh) = 17; - } = 2; -} = 100003; -#ifdef WANT_NFS3 -program NFS3_PROGRAM { - version NFS_V3 { - void - NFSPROC3_NULL(void) = 0; - - GETATTR3res - NFSPROC3_GETATTR(GETATTR3args) = 1; - - SETATTR3res - NFSPROC3_SETATTR(SETATTR3args) = 2; - - LOOKUP3res - NFSPROC3_LOOKUP(LOOKUP3args) = 3; - - ACCESS3res - NFSPROC3_ACCESS(ACCESS3args) = 4; - - READLINK3res - NFSPROC3_READLINK(READLINK3args) = 5; - - READ3res - NFSPROC3_READ(READ3args) = 6; - - WRITE3res - NFSPROC3_WRITE(WRITE3args) = 7; - - CREATE3res - NFSPROC3_CREATE(CREATE3args) = 8; - - MKDIR3res - NFSPROC3_MKDIR(MKDIR3args) = 9; - - SYMLINK3res - NFSPROC3_SYMLINK(SYMLINK3args) = 10; - - MKNOD3res - NFSPROC3_MKNOD(MKNOD3args) = 11; - - REMOVE3res - NFSPROC3_REMOVE(REMOVE3args) = 12; - - RMDIR3res - NFSPROC3_RMDIR(RMDIR3args) = 13; - - RENAME3res - NFSPROC3_RENAME(RENAME3args) = 14; - - LINK3res - NFSPROC3_LINK(LINK3args) = 15; - - READDIR3res - NFSPROC3_READDIR(READDIR3args) = 16; - - READDIRPLUS3res - NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17; - - FSSTAT3res - NFSPROC3_FSSTAT(FSSTAT3args) = 18; - - FSINFO3res - NFSPROC3_FSINFO(FSINFO3args) = 19; - - PATHCONF3res - NFSPROC3_PATHCONF(PATHCONF3args) = 20; - - COMMIT3res - NFSPROC3_COMMIT(COMMIT3args) = 21; - } = 3; -} = 100003; -#endif - diff --git a/rtemsNfs-1.1/rtems-filesystem-patch b/rtemsNfs-1.1/rtems-filesystem-patch deleted file mode 100644 index c2d7861..0000000 --- a/rtemsNfs-1.1/rtems-filesystem-patch +++ /dev/null @@ -1,860 +0,0 @@ -# Diffed against OAR_orig (ss-20020301) on Sun Nov 3 00:24:13 PST 2002 -# T.S. - -For more information about this patch consult README (CAVEATS section). - -To apply this patch, - -chdir to c/src/lib/libc - -and issue - - patch -p0 < this_file - -It is always a good idea to try a "dry-run" before applying a patch: - - patch --dry-run -p0 < this_file - -Index: Makefile.am -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/Makefile.am,v -retrieving revision 1.1.1.2 -retrieving revision 1.2 -diff -c -r1.1.1.2 -r1.2 -*** Makefile.am 7 Mar 2002 01:53:46 -0000 1.1.1.2 ---- Makefile.am 28 Mar 2002 20:59:16 -0000 1.2 -*************** -*** 1,5 **** - ## -! ## $Id$ - ## - - AUTOMAKE_OPTIONS = foreign 1.4 ---- 1,5 ---- - ## -! ## $Id$ - ## - - AUTOMAKE_OPTIONS = foreign 1.4 -*************** -*** 32,37 **** ---- 32,39 ---- - - MALLOC_C_FILES = malloc.c mallocfreespace.c __brk.c __sbrk.c - -+ ENVIRON_C_FILES = envlock.c -+ - PASSWORD_GROUP_C_FILES = getpwent.c getgrent.c - - TERMINAL_IDENTIFICATION_C_FILES = ctermid.c isatty.c ttyname.c ttyname_r.c -*************** -*** 42,48 **** - UNIX_LIBC_C_FILES = unixlibc.c hosterr.c - - COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ -! $(MALLOC_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ - $(ASSOCIATION_C_FILES) - - UNIX_C_FILES = $(UNIX_LIBC_C_FILES) ---- 44,50 ---- - UNIX_LIBC_C_FILES = unixlibc.c hosterr.c - - COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ -! $(MALLOC_C_FILES) $(ENVIRON_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ - $(ASSOCIATION_C_FILES) - - UNIX_C_FILES = $(UNIX_LIBC_C_FILES) -Index: base_fs.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/base_fs.c,v -retrieving revision 1.1.1.1 -diff -c -r1.1.1.1 base_fs.c -*** base_fs.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 ---- base_fs.c 26 Oct 2002 02:45:15 -0000 -*************** -*** 49,54 **** ---- 49,55 ---- - int status; - rtems_filesystem_mount_table_entry_t *entry; - rtems_filesystem_mount_table_t *mt; -+ rtems_filesystem_location_info_t loc; - - /* - * Set the default umask to "022". -*************** -*** 75,82 **** - rtems_fatal_error_occurred( 0xABCD0002 ); - - rtems_filesystem_link_counts = 0; - rtems_filesystem_root = entry->mt_fs_root; -! rtems_filesystem_current = rtems_filesystem_root; - - - /* ---- 76,113 ---- - rtems_fatal_error_occurred( 0xABCD0002 ); - - rtems_filesystem_link_counts = 0; -+ -+ /* setup the 'current' and 'root' directories -+ * -+ * NOTE: cloning the pathlocs is not strictly -+ * necessary. Since we implicitely let -+ * all threads that don't call -+ * libio_set_private_env() share the same -+ * (initial) 'root' and 'current' locs, -+ * we (also implicitely) assume that the -+ * root filesystem doesn't care about -+ * reference counts. -+ * I just inserted the code snippet below -+ * to remind everybody of the fact by -+ * making it more explicit... -+ * Ideally, every thread would have to -+ * call either share_private_env() or -+ * set_private_env() - but then: that's -+ * gonna hit performance. -+ * -+ * Till Straumann, 10/25/2002 -+ */ - rtems_filesystem_root = entry->mt_fs_root; -! /* Clone the root pathloc */ -! rtems_filesystem_evaluate_path("/", 0, &loc, 0); -! rtems_filesystem_root = loc; -! /* One more clone for the current node */ -! rtems_filesystem_evaluate_path("/", 0, &loc, 0); -! rtems_filesystem_current = loc; -! -! /* Note: the global_env's refcnt doesn't matter -! * as the global env is never released -! */ - - - /* -Index: chroot.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/chroot.c,v -retrieving revision 1.1.1.2 -diff -c -r1.1.1.2 chroot.c -*** chroot.c 7 Mar 2002 01:53:47 -0000 1.1.1.2 ---- chroot.c 29 Oct 2002 03:01:47 -0000 -*************** -*** 38,51 **** - rtems_set_errno_and_return_minus_one( ENOTSUP ); - }; - -- loc = rtems_filesystem_root; /* save the value */ -- - result = chdir(pathname); - if (result) { -- rtems_filesystem_root = loc; /* restore the value */ - rtems_set_errno_and_return_minus_one( errno ); - }; -! rtems_filesystem_root = rtems_filesystem_current; - - return 0; - } ---- 38,53 ---- - rtems_set_errno_and_return_minus_one( ENOTSUP ); - }; - - result = chdir(pathname); - if (result) { - rtems_set_errno_and_return_minus_one( errno ); - }; -! /* clone the new root location */ -! if (rtems_filesystem_evaluate_path(".", 0, &loc, 0)) { -! rtems_set_errno_and_return_minus_one( errno ); -! } -! rtems_filesystem_freenode(&rtems_filesystem_root); -! rtems_filesystem_root = loc; - - return 0; - } -Index: eval.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/eval.c,v -retrieving revision 1.1.1.2 -retrieving revision 1.2 -diff -c -r1.1.1.2 -r1.2 -*** eval.c 7 Mar 2002 01:53:48 -0000 1.1.1.2 ---- eval.c 29 Oct 2002 21:03:50 -0000 1.2 -*************** -*** 10,16 **** - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H ---- 10,16 ---- - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H -*************** -*** 60,76 **** - - if ( (result == 0) && follow_link ) { - -! if ( !pathloc->ops->node_type_h ) - rtems_set_errno_and_return_minus_one( ENOTSUP ); - - type = (*pathloc->ops->node_type_h)( pathloc ); - - if ( ( type == RTEMS_FILESYSTEM_HARD_LINK ) || - ( type == RTEMS_FILESYSTEM_SYM_LINK ) ) { - -! if ( !pathloc->ops->eval_link_h ) - rtems_set_errno_and_return_minus_one( ENOTSUP ); - - result = (*pathloc->ops->eval_link_h)( pathloc, flags ); - - } ---- 60,93 ---- - - if ( (result == 0) && follow_link ) { - -! if ( !pathloc->ops->node_type_h ) { -! rtems_filesystem_freenode(pathloc); - rtems_set_errno_and_return_minus_one( ENOTSUP ); -+ } - - type = (*pathloc->ops->node_type_h)( pathloc ); - - if ( ( type == RTEMS_FILESYSTEM_HARD_LINK ) || - ( type == RTEMS_FILESYSTEM_SYM_LINK ) ) { - -! if ( !pathloc->ops->eval_link_h ) { -! rtems_filesystem_freenode(pathloc); - rtems_set_errno_and_return_minus_one( ENOTSUP ); -+ } - -+ /* what to do with the valid node pathloc points to -+ * if eval_link_h() fails? -+ * Let the FS implementation deal with this case. It -+ * should probably free pathloc in either case: -+ * - if the link evaluation fails, it must free the -+ * original (valid) pathloc because we are going -+ * to return -1 and hence the FS generics won't -+ * cleanup pathloc -+ * - if the link evaluation is successful, the updated -+ * pathloc will be passed up (and eventually released). -+ * Hence, the (valid) original node that we submit to -+ * eval_link_h() should be released by the handler. -+ */ - result = (*pathloc->ops->eval_link_h)( pathloc, flags ); - - } -Index: fchdir.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/fchdir.c,v -retrieving revision 1.1.1.2 -diff -c -r1.1.1.2 fchdir.c -*** fchdir.c 7 Mar 2002 01:53:48 -0000 1.1.1.2 ---- fchdir.c 25 Oct 2002 23:59:03 -0000 -*************** -*** 29,34 **** ---- 29,35 ---- - ) - { - rtems_libio_t *iop; -+ rtems_filesystem_location_info_t loc; - - rtems_libio_check_fd( fd ); - iop = rtems_libio_iop( fd ); -*************** -*** 65,74 **** - * this node which we are making here. I can - * see the freenode interface but do not see - * allocnode node interface. It maybe node_type. - */ - - rtems_filesystem_current = iop->pathinfo; - - return 0; - } -- ---- 66,80 ---- - * this node which we are making here. I can - * see the freenode interface but do not see - * allocnode node interface. It maybe node_type. -+ * -+ * FIXEC: T.Straumann: it is evaluate_path() - */ - - rtems_filesystem_current = iop->pathinfo; - -+ /* clone the current node */ -+ rtems_filesystem_evaluate_path(".", 0, &loc, 0); -+ rtems_filesystem_current = loc; -+ - return 0; - } -Index: getgrent.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/getgrent.c,v -retrieving revision 1.1.1.1 -diff -c -r1.1.1.1 getgrent.c -*** getgrent.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 ---- getgrent.c 27 Oct 2002 18:24:20 -0000 -*************** -*** 50,63 **** ---- 50,69 ---- - ) - { - FILE *fp; -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if ((fp = fopen ("/etc/group", "r")) == NULL) { - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 72,84 **** ---- 78,94 ---- - if (!strcmp (groupname, name)) { - fclose (fp); - *result = grp; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return 0; - } - } - fclose (fp); - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 104,118 **** ---- 114,134 ---- - ) - { - FILE *fp; -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - - - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if ((fp = fopen ("/etc/group", "r")) == NULL) { - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 128,140 **** ---- 144,160 ---- - if (gid == gr_group.gr_gid) { - fclose (fp); - *result = grp; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return 0; - } - } - fclose (fp); - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 174,188 **** ---- 194,214 ---- - void - setgrent () - { -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if (group_fp != NULL) - fclose (group_fp); - - group_fp = fopen ("/etc/group", "r"); -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - } - - void -Index: getpwent.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/getpwent.c,v -retrieving revision 1.1.1.1 -diff -c -r1.1.1.1 getpwent.c -*** getpwent.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 ---- getpwent.c 27 Oct 2002 18:18:52 -0000 -*************** -*** 97,110 **** ---- 97,116 ---- - ) - { - FILE *fp; -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if ((fp = fopen ("/etc/passwd", "r")) == NULL) { - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 123,135 **** ---- 129,145 ---- - if (!strcmp (logname, name)) { - fclose (fp); - *result = pwd; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return 0; - } - } - fclose (fp); - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 155,168 **** ---- 165,184 ---- - ) - { - FILE *fp; -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if ((fp = fopen ("/etc/passwd", "r")) == NULL) { - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 181,193 **** ---- 197,213 ---- - if (uid == pwd->pw_uid) { - fclose (fp); - *result = pwd; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return 0; - } - } - fclose (fp); - errno = EINVAL; -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - return -1; - } - -*************** -*** 230,244 **** ---- 250,270 ---- - - void setpwent( void ) - { -+ #if 0 - rtems_user_env_t * aux=rtems_current_user_env; /* save */ -+ #endif - init_etc_passwd_group(); -+ #if 0 - rtems_current_user_env=&rtems_global_user_env; /* set root */ -+ #endif - - if (passwd_fp != NULL) - fclose (passwd_fp); - - passwd_fp = fopen ("/etc/passwd", "r"); -+ #if 0 - rtems_current_user_env=aux; /* restore */ -+ #endif - } - - void endpwent( void ) -Index: mknod.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/mknod.c,v -retrieving revision 1.1.1.2 -retrieving revision 1.2 -diff -c -r1.1.1.2 -r1.2 -*** mknod.c 7 Mar 2002 01:53:51 -0000 1.1.1.2 ---- mknod.c 29 Oct 2002 21:03:50 -0000 1.2 -*************** -*** 12,18 **** - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H ---- 12,18 ---- - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H -*************** -*** 49,55 **** - rtems_filesystem_get_start_loc( pathname, &i, &temp_loc ); - - if ( !temp_loc.ops->evalformake_h ) { -- rtems_filesystem_freenode( &temp_loc ); - rtems_set_errno_and_return_minus_one( ENOTSUP ); - } - ---- 49,54 ---- -Index: mount.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/mount.c,v -retrieving revision 1.1.1.1 -diff -c -r1.1.1.1 mount.c -*** mount.c 14 Dec 2001 22:52:33 -0000 1.1.1.1 ---- mount.c 30 Oct 2002 06:39:09 -0000 -*************** -*** 14,20 **** - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H ---- 14,20 ---- - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - */ - - #if HAVE_CONFIG_H -*************** -*** 101,106 **** ---- 101,113 ---- - return -1; - } - -+ /* Do they support being mounted at all ? */ -+ if ( !fs_ops->fsmount_me_h ) { -+ errno = ENOTSUP; -+ goto cleanup_and_bail; -+ } -+ -+ - /* - * Allocate a mount table entry - */ -*************** -*** 140,145 **** ---- 147,158 ---- - */ - - loc_to_free = &loc; -+ -+ if ( !loc.ops->node_type_h ) { -+ errno = ENOTSUP; -+ goto cleanup_and_bail; -+ } -+ - if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { - errno = ENOTDIR; - goto cleanup_and_bail; -*************** -*** 198,210 **** - temp_mt_entry->mt_point_node.mt_entry = NULL; - } - -! if ( !fs_ops->fsmount_me_h ) { -! errno = ENOTSUP; - goto cleanup_and_bail; - } -- -- if ( fs_ops->fsmount_me_h( temp_mt_entry ) ) -- goto cleanup_and_bail; - - /* - * Add the mount table entry to the mount table chain ---- 211,223 ---- - temp_mt_entry->mt_point_node.mt_entry = NULL; - } - -! if ( fs_ops->fsmount_me_h( temp_mt_entry ) ) { -! /* try to undo the mount operation */ -! if ( loc.ops->unmount_h ) { -! loc.ops->unmount_h( temp_mt_entry ); -! } - goto cleanup_and_bail; - } - - /* - * Add the mount table entry to the mount table chain -Index: newlibc.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/newlibc.c,v -retrieving revision 1.1.1.1 -retrieving revision 1.3 -diff -c -r1.1.1.1 -r1.3 -*** newlibc.c 14 Dec 2001 22:52:33 -0000 1.1.1.1 ---- newlibc.c 16 Apr 2002 19:41:03 -0000 1.3 -*************** -*** 9,15 **** - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - * - */ - ---- 9,15 ---- - * found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. - * -! * $Id$ - * - */ - -Index: privateenv.c -=================================================================== -RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/privateenv.c,v -retrieving revision 1.1.1.2 -diff -c -r1.1.1.2 privateenv.c -*** privateenv.c 7 Mar 2002 01:53:51 -0000 1.1.1.2 ---- privateenv.c 27 Oct 2002 18:35:34 -0000 -*************** -*** 23,47 **** - #include - #include - - rtems_status_code rtems_libio_set_private_env(void) { -! rtems_status_code sc; -! rtems_id task_id; - - sc=rtems_task_ident(RTEMS_SELF,0,&task_id); - if (sc != RTEMS_SUCCESSFUL) return sc; - - /* Only for the first time a malloc is necesary */ -! if (rtems_current_user_env==&rtems_global_user_env) { -! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free); -! if (sc != RTEMS_SUCCESSFUL) return sc; -! rtems_current_user_env = malloc(sizeof(rtems_user_env_t)); -! if (!rtems_current_user_env) - return RTEMS_NO_MEMORY; - }; - -- /* the side effect desired . chroot("/") */ - *rtems_current_user_env = rtems_global_user_env; /* get the global values*/ - rtems_current_user_env->task_id=task_id; /* mark the local values*/ - - return RTEMS_SUCCESSFUL; - } ---- 23,92 ---- - #include - #include - -+ extern Chain_Control rtems_filesystem_mount_table_control; -+ -+ #define THE_ROOT_FS_LOC \ -+ (((rtems_filesystem_mount_table_entry_t*)\ -+ rtems_filesystem_mount_table_control.first)->mt_fs_root) -+ -+ /* cleanup a user environment -+ * NOTE: this must be called with -+ * thread dispatching disabled! -+ */ -+ static void -+ free_user_env(rtems_user_env_t *env) -+ { -+ if (env != &rtems_global_user_env -+ && --env->refcnt <= 0) { -+ rtems_filesystem_freenode( &env->current_directory); -+ rtems_filesystem_freenode( &env->root_directory); -+ free(env); -+ } -+ } -+ - rtems_status_code rtems_libio_set_private_env(void) { -! rtems_status_code sc; -! rtems_id task_id; -! rtems_filesystem_location_info_t loc; - - sc=rtems_task_ident(RTEMS_SELF,0,&task_id); - if (sc != RTEMS_SUCCESSFUL) return sc; - - /* Only for the first time a malloc is necesary */ -! if (rtems_current_user_env==&rtems_global_user_env) { -! rtems_user_env_t *tmp = malloc(sizeof(rtems_user_env_t)); -! if (!tmp) - return RTEMS_NO_MEMORY; -+ -+ tmp->refcnt = 1; -+ -+ sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); -+ if (sc != RTEMS_SUCCESSFUL) { -+ /* don't use free_user_env because the pathlocs are -+ * not initialized yet -+ */ -+ free(tmp); -+ return sc; -+ } -+ rtems_current_user_env = tmp; - }; - - *rtems_current_user_env = rtems_global_user_env; /* get the global values*/ - rtems_current_user_env->task_id=task_id; /* mark the local values*/ -+ -+ /* get a clean root */ -+ rtems_filesystem_root = THE_ROOT_FS_LOC; -+ -+ /* Clone the pathlocs. In contrast to most other -+ * code we must _not_ free the original locs because -+ * what we are trying to do here is forking off -+ * clones. -+ */ -+ -+ rtems_filesystem_evaluate_path("/", 0, &loc, 0); -+ rtems_filesystem_root = loc; -+ rtems_filesystem_evaluate_path("/", 0, &loc, 0); -+ rtems_filesystem_current = loc; - - return RTEMS_SUCCESSFUL; - } -*************** -*** 51,56 **** ---- 96,115 ---- - * Task_id (remote) and RTEMS_SELF(current). - */ - -+ /* NOTE: -+ * -+ * THIS CODE HAS NO PROTECTION IMPLEMENTED -+ * -+ * Tasks who wish to share their environments must -+ * -+ * a) assert that no participants are concurrently -+ * executing -+ * libio_share_private_env() and/or libio_set_private_env() -+ * -+ * b) mutex access to rtems_filesystem_current, rtems_filesytem_root -+ * while changing any of those (chdir(), chroot()). -+ */ -+ - rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { - rtems_status_code sc; - rtems_user_env_t * shared_user_env; -*************** -*** 61,81 **** - - if (rtems_current_user_env->task_id==current_task_id) { - /* kill the current user env & task_var*/ -! free(rtems_current_user_env); - sc = rtems_task_variable_delete(RTEMS_SELF,(void*)&rtems_current_user_env); - if (sc != RTEMS_SUCCESSFUL) return sc; - }; - - sc = rtems_task_variable_get(task_id,(void*)&rtems_current_user_env, - (void*)&shared_user_env ); -! if (sc != RTEMS_SUCCESSFUL) return sc; - -! /* don't free(NULL'ed) at the task_delete. It is a shared var... */ -! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,NULL); -! if (sc != RTEMS_SUCCESSFUL) return sc; - - /* the current_user_env is the same pointer that remote env */ - rtems_current_user_env = shared_user_env; - - return RTEMS_SUCCESSFUL; - } ---- 120,152 ---- - - if (rtems_current_user_env->task_id==current_task_id) { - /* kill the current user env & task_var*/ -! rtems_user_env_t *tmp = rtems_current_user_env; - sc = rtems_task_variable_delete(RTEMS_SELF,(void*)&rtems_current_user_env); - if (sc != RTEMS_SUCCESSFUL) return sc; -+ free_user_env(tmp); - }; - -+ /* AT THIS POINT, rtems_current_user_env is DANGLING */ -+ - sc = rtems_task_variable_get(task_id,(void*)&rtems_current_user_env, - (void*)&shared_user_env ); -! if (sc != RTEMS_SUCCESSFUL) -! goto bailout; - -! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); -! if (sc != RTEMS_SUCCESSFUL) -! goto bailout; - - /* the current_user_env is the same pointer that remote env */ - rtems_current_user_env = shared_user_env; - -+ /* increase the reference count */ -+ rtems_current_user_env->refcnt++; -+ - return RTEMS_SUCCESSFUL; -+ -+ bailout: -+ /* fallback to the global env */ -+ rtems_current_user_env = &rtems_global_user_env; -+ return sc; - } diff --git a/rtemsNfs-1.1/src/Makefile b/rtemsNfs-1.1/src/Makefile deleted file mode 100644 index 584ee00..0000000 --- a/rtemsNfs-1.1/src/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -# -# $Id$ -# -# Templates/Makefile.leaf -# Template leaf node Makefile -# - -# if you have CEXP set this variable to 'YES' -# and some "help" info will be compiled in. -HAVE_CEXP=NO - -# C source names, if any, go here -- minus the .c -C_PIECES_YES=rpcio nfs sock_mbuf xdr_mbuf dirutils rpcio.modini nfs.modini cexphelp -C_PIECES_NO=rpcio nfs sock_mbuf xdr_mbuf - -C_PIECES=$(C_PIECES_$(HAVE_CEXP)) - -C_FILES=$(C_PIECES:%=%.c) -C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) - -# C++ source names, if any, go here -- minus the .cc -CC_PIECES= -CC_FILES=$(CC_PIECES:%=%.cc) -CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o) - -H_FILES=librtemsNfs.h rpcio.h -INST_HEADERS=librtemsNfs.h - -# Assembly source names, if any, go here -- minus the .S -S_PIECES= -S_FILES=$(S_PIECES:%=%.S) -S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o) - -SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) -OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES) $(wildcard ../proto/$(ARCH)/*.o) - -PGMS=${ARCH}/nfs.obj ${ARCH}/rpcio.obj ${ARCH}/dirutils.obj - -LIBNAME=librtemsNfs.a - -LIB=$(ARCH)/$(LIBNAME) - -include $(RTEMS_MAKEFILE_PATH)/Makefile.inc -include $(RTEMS_CUSTOM) -include $(RTEMS_ROOT)/make/lib.cfg - -# -# (OPTIONAL) Add local stuff here using += -# - -DEFS_CEXP_YES=-DHAVE_CEXP - -DEFINES += $(DEFS_CEXP_$(HAVE_CEXP)) - -CPPFLAGS += -I. -I../proto - -CFLAGS += - -# -# CFLAGS_DEBUG_V are used when the `make debug' target is built. -# To link your application with the non-optimized RTEMS routines, -# uncomment the following line: -# CFLAGS_DEBUG_V += -qrtems_debug -# - -LDFLAGS += - -# -# Add your list of files to delete here. The config files -# already know how to delete some stuff, so you may want -# to just run 'make clean' first to see what gets missed. -# 'make clobber' already includes 'make clean' -# - -#CLEAN_ADDITIONS += xxx-your-debris-goes-here -CLOBBER_ADDITIONS += - -ifndef RTEMS_SITE_INSTALLDIR -RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE) -endif - -%nfs.obj: %nfs.o %nfs.modini.o - $(LD) -r -o $@ $^ -L../proto/$(ARCH) -lnfsprot - -%rpcio.obj: %rpcio.o %sock_mbuf.o %xdr_mbuf.o %rpcio.modini.o - $(LD) -r -o $@ $^ - -%dirutils.obj: %dirutils.o - $(LD) -r -o $@ $^ - -$(LIB): $(OBJS) - $(make-library) - -all: ${ARCH} $(SRCS) $(PGMS) $(LIB) - -tar: - echo not implemented - -# Install the program(s), appending _g or _p as appropriate. -# for include files, just use $(INSTALL_CHANGE) -install: all - $(INSTALL_VARIANT) -m 555 ${PGMS} ${RTEMS_SITE_INSTALLDIR}/bin - $(INSTALL_VARIANT) -m 555 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib - $(INSTALL_CHANGE) -m 444 ${INST_HEADERS} ${RTEMS_SITE_INSTALLDIR}/include diff --git a/rtemsNfs-1.1/src/cexphelp.c b/rtemsNfs-1.1/src/cexphelp.c deleted file mode 100644 index d062ed1..0000000 --- a/rtemsNfs-1.1/src/cexphelp.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -CEXP_HELP_TAB_BEGIN(rtemsNfs) - HELP( -"Mount a remote filesystem (NFS). The mount point (must not be a NFS dir)\n" -"is created on the fly if not existing already.\n" -"uid/gid to use may be specified:\n" -" hostspec: [uid.gid@]hostname_or_ipaddr\n" - , int, nfsMount, (char *hostspec, char *exportdir, char *mntpoint) - ), - HELP( -"Print all currently mounted NFS directories to open file handle.\n" -"Pass f = 0 to print to stdout\n" - , int, nfsMountsShow, (FILE *f) - ), -CEXP_HELP_TAB_END diff --git a/rtemsNfs-1.1/src/dirutils.c b/rtemsNfs-1.1/src/dirutils.c deleted file mode 100644 index 91b1858..0000000 --- a/rtemsNfs-1.1/src/dirutils.c +++ /dev/null @@ -1,323 +0,0 @@ -/* $Id$ */ - -/* very crude and basic fs utilities for testing the NFS */ - -/* Till Straumann, , 10/2002 */ - -/* - * Copyright 2002, Stanford University and - * Till Straumann - * - * Stanford Notice - * *************** - * - * Acknowledgement of sponsorship - * * * * * * * * * * * * * * * * * - * This software was produced by the Stanford Linear Accelerator Center, - * Stanford University, under Contract DE-AC03-76SFO0515 with the Department - * of Energy. - * - * Government disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, - * or assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately - * owned rights. - * - * Stanford disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * This product is subject to the EPICS open license - * - - - - - - - - - - - - - - - - - - - - - - - - - - * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php - * for more information. - * - * Maintenance of notice - * - - - - - - - - - - - - * In the interest of clarity regarding the origin and status of this - * software, Stanford University requests that any recipient of it maintain - * this notice affixed to any distribution by the recipient that contains a - * copy or derivative of this software. - */ - -#ifdef __vxworks -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_CEXP -#include -#endif - -#define BUFFERSZ 10000 - -#ifndef __vxworks -int -pwd(void) -{ -char buf[MAXPATHLEN]; - - if ( !getcwd(buf,MAXPATHLEN)) { - perror("getcwd"); - return -1; - } else { - printf("%s\n",buf); - } - return 0; -} - -static int -ls_r(char *path, char *chpt, char *name, struct stat *buf) -{ -char *t; - sprintf(chpt, "/%s", name); - if (lstat(path,buf)) { - fprintf(stderr,"stat(%s): %s\n", path, strerror(errno)); - return -1; - } - switch ( buf->st_mode & S_IFMT ) { - case S_IFSOCK: - case S_IFIFO: t = "|"; break; - - default: - case S_IFREG: - case S_IFBLK: - case S_IFCHR: - t = ""; break; - case S_IFDIR: - t = "/"; break; - case S_IFLNK: - t = "@"; break; - } - - printf("%10li, %10lib, %5i.%-5i 0%04o %s%s\n", - buf->st_ino, - buf->st_size, - buf->st_uid, - buf->st_gid, - buf->st_mode & ~S_IFMT, - name, - t); - *chpt = 0; - return 0; -} - -int -ls(char *dir, char *opts) -{ -struct dirent *de; -char path[MAXPATHLEN+1]; -char *chpt; -DIR *dp = 0; -int rval = -1; -struct stat buf; - - if ( !dir ) - dir = "."; - - strncpy(path, dir, MAXPATHLEN); - path[MAXPATHLEN] = 0; - chpt = path+strlen(path); - - if ( !(dp=opendir(dir)) ) { - perror("opendir"); - goto cleanup; - } - - while ( (de = readdir(dp)) ) { - ls_r(path, chpt, de->d_name, &buf); - } - - rval = 0; - -cleanup: - if (dp) - closedir(dp); - return rval; -} -#endif - -#if 0 - fprintf(stderr, "usage: cp(""from"",[""to""[,""-f""]]\n"); - fprintf(stderr, " ""to""==NULL -> stdout\n"); - fprintf(stderr, " ""-f"" -> overwrite existing file\n"); -#endif - -int -cp(char *from, char *to, char *opts) -{ -struct stat st; -int got,put,tot; -char *buf = 0; -int rval = -1; -int ffd = -1; -int tfd = -1; -int flags = O_CREAT | O_WRONLY | O_TRUNC | O_EXCL; - - if (from) { - - if ((ffd=open(from,O_RDONLY,0)) < 0) { - fprintf(stderr, - "Opening %s for reading: %s\n", - from, - strerror(errno)); - goto cleanup; - } - - if (fstat(ffd, &st)) { - fprintf(stderr, - "rstat(%s): %s\n", - from, - strerror(errno)); - goto cleanup; - } - - - if (!S_ISREG(st.st_mode)) { - fprintf(stderr,"Refuse to copy a non-regular file\n"); - errno = EINVAL; - goto cleanup; - } - - } else { - ffd = fileno(stdin); - st.st_mode = 0644; - } - - if (opts && strchr(opts,'f')) - flags &= ~ O_EXCL; - - if (to) { - if ((tfd=open(to,flags,st.st_mode)) < 0) { - fprintf(stderr, - "Opening %s for writing: %s\n", - to, - strerror(errno)); - goto cleanup; - } - } else { - tfd = fileno(stdout); - } - - if ( !(buf = malloc(BUFFERSZ)) ) { - fprintf(stderr,"cp: unable to allocate buffer - out of memory\n"); - errno = ENOMEM; - goto cleanup; - } - - tot = 0; - while ( (got=read(ffd,buf,BUFFERSZ)) > 0 ) { - if (got !=(put=write(tfd,buf,got))) { - if (put<0) { - fprintf(stderr,"Write error: %s\n",strerror(errno)); - } else { - fprintf(stderr,"Write error: unable to write whole block\n"); - } - goto cleanup; - } - tot += got; - } - if (got < 0) { - fprintf(stderr,"Read error: %s\n",strerror(errno)); - goto cleanup; - } - rval = 0; - -cleanup: - free(buf); - - if (from && ffd>=0) - close(ffd); - if (to && tfd>=0) - close(tfd); - - return rval; -} - -int -ln(char *to, char *name, char *opts) -{ - if (!to) { - fprintf(stderr,"ln: need 'to' argument\n"); - return -1; - } - if (!name) { - if ( !(name = strrchr(to,'/')) ) { - fprintf(stderr, - "ln: 'unable to link %s to %s\n", - to,to); - return -1; - } - name++; - } - if (opts || strchr(opts,'s')) { - if (symlink(name,to)) { - fprintf(stderr,"symlink: %s\n",strerror(errno)); - return -1; - } - } else { - if (link(name,to)) { - fprintf(stderr,"hardlink: %s\n",strerror(errno)); - return -1; - } - } - return 0; -} - -int -rm(char *path) -{ - return unlink(path); -} - -int -cd(char *path) -{ - return chdir(path); -} - -#ifdef HAVE_CEXP -static CexpHelpTabRec _cexpHelpTabDirutils[]={ - HELP( -"copy a file: cp(""from"",[""to""[,""-f""]])\n\ - from = NULL <-- stdin\n\ - to = NULL --> stdout\n\ - option -f: overwrite existing file\n", - int, - cp, (char *from, char *to, char *options) - ), - HELP( -"list a directory: ls([""dir""])\n", - int, - ls, (char *dir) - ), - HELP( -"remove a file\n", - int, - rm, (char *path) - ), - HELP( -"change the working directory\n", - int, - cd, (char *path) - ), - HELP( -"create a link: ln(""to"",""name"",""[-s]""\n\ - -s creates a symlink\n", - int, - ln, (char *to, char *name, char *options) - ), - HELP("",,0,) -}; -#endif diff --git a/rtemsNfs-1.1/src/librtemsNfs.h b/rtemsNfs-1.1/src/librtemsNfs.h deleted file mode 100644 index 880842c..0000000 --- a/rtemsNfs-1.1/src/librtemsNfs.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef LIB_RTEMS_NFS_CLIENT_H -#define LIB_RTEMS_NFS_CLIENT_H -/* $Id$ */ - -/* public interface to the NFS client library for RTEMS */ - -/* Author: Till Straumann 2002-2003 */ - -/* - * Copyright 2002-2003, Stanford University and - * Till Straumann - * - * Stanford Notice - * *************** - * - * Acknowledgement of sponsorship - * * * * * * * * * * * * * * * * * - * This software was produced by the Stanford Linear Accelerator Center, - * Stanford University, under Contract DE-AC03-76SFO0515 with the Department - * of Energy. - * - * Government disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, - * or assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately - * owned rights. - * - * Stanford disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * This product is subject to the EPICS open license - * - - - - - - - - - - - - - - - - - - - - - - - - - - * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php - * for more information. - * - * Maintenance of notice - * - - - - - - - - - - - - * In the interest of clarity regarding the origin and status of this - * software, Stanford University requests that any recipient of it maintain - * this notice affixed to any distribution by the recipient that contains a - * copy or derivative of this software. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef HAVE_CEXP_H -#include -#endif - -/* RPCIO driver interface. - * If you need RPCIO for other purposes than NFS - * you may want to include -#include "rpcio.h" - */ - -/* Initialize the driver - * - * RETURNS: 0 on success, -1 on failure - */ -int -rpcUdpInit(void); - -/* Cleanup/Stop - * - * RETURNS: 0 on success, nonzero if still in use - */ -int -rpcUdpCleanup(void); - -/* NFS driver interface */ - -/* Initialize the NFS driver. - * - * NOTE: The RPCIO driver must have been initialized prior to - * calling this. - * - * ARGS: depth of the small and big - * transaction pools, i.e. how - * many transactions (buffers) - * should always be kept around. - * - * (If more transactions are needed, - * they are created and destroyed - * on the fly). - * - * Supply zero values to have the - * driver chose reasonable defaults. - */ -int -nfsInit(int smallPoolDepth, int bigPoolDepth); - -/* Driver cleanup code - * - * RETURNS: 0 on success, nonzero if still in use - */ -int -nfsCleanup(void); - -/* Dump a list of the currently mounted NFS to a file - * (stdout is used in case f==NULL) - */ -int -nfsMountsShow(FILE *f); - -/* convenience wrapper - * - * NOTE: this routine calls NON-REENTRANT - * gethostbyname() if the host is - * not in 'dot' notation. - */ -int -nfsMount(char *uidhost, char *path, char *mntpoint); - -/* Alternatively, a pointer to the filesystem operations - * table can be supplied to the native RTEMS (NON-POSIX!) - * 'mount()' call. - * Supply a ":" string - * for 'device' argument to 'mount()'. - */ -extern struct _rtems_filesystem_operations_table nfs_fs_ops; - -/* A utility routine to find the path leading to a - * rtems_filesystem_location_info_t node. - * - * This should really be present in libcsupport... - * - * INPUT: 'loc' and a buffer 'buf' (length 'len') to hold the - * path. - * OUTPUT: path copied into 'buf' - * - * RETURNS: 0 on success, RTEMS error code on error. - */ -rtems_status_code -rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc); -#endif diff --git a/rtemsNfs-1.1/src/nfs.c b/rtemsNfs-1.1/src/nfs.c deleted file mode 100644 index b695a76..0000000 --- a/rtemsNfs-1.1/src/nfs.c +++ /dev/null @@ -1,3299 +0,0 @@ -/* $Id$ */ - -/* NFS client implementation for RTEMS; hooks into the RTEMS filesystem */ - -/* Author: Till Straumann 2002 */ - -/* - * Copyright 2002, Stanford University and - * Till Straumann - * - * Stanford Notice - * *************** - * - * Acknowledgement of sponsorship - * * * * * * * * * * * * * * * * * - * This software was produced by the Stanford Linear Accelerator Center, - * Stanford University, under Contract DE-AC03-76SFO0515 with the Department - * of Energy. - * - * Government disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, - * or assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately - * owned rights. - * - * Stanford disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * This product is subject to the EPICS open license - * - - - - - - - - - - - - - - - - - - - - - - - - - - * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php - * for more information. - * - * Maintenance of notice - * - - - - - - - - - - - - * In the interest of clarity regarding the origin and status of this - * software, Stanford University requests that any recipient of it maintain - * this notice affixed to any distribution by the recipient that contains a - * copy or derivative of this software. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include "rpcio.h" - -#ifdef HAVE_CEXP_H -#include -#endif - - -/* Configurable parameters */ - -/* Estimated average length of a filename (including terminating 0). - * This was calculated by doing - * - * find -print -exec basename '{}' \; > feil - * wc feil - * - * AVG_NAMLEN = (num_chars + num_lines)/num_lines - */ -#define CONFIG_AVG_NAMLEN 10 - -#define CONFIG_NFS_SMALL_XACT_SIZE 800 /* size of RPC arguments for non-write ops */ -/* lifetime of NFS attributes in a NfsNode; - * the time is in seconds and the lifetime is - * infinite if the symbol is #undef - */ -#define CONFIG_ATTR_LIFETIME 10/*secs*/ - -/* dont change this without changing the maximal write size */ -#define CONFIG_NFS_BIG_XACT_SIZE UDPMSGSIZE /* dont change this */ - -/* The real values for these are specified further down */ -#define NFSCALL_TIMEOUT (&_nfscalltimeout) -#define MNTCALL_TIMEOUT (&_nfscalltimeout) -static struct timeval _nfscalltimeout = { 10, 0 }; /* {secs, us } */ - -/* More or less fixed constants; in particular, NFS3 is not supported */ -#define DELIM '/' -#define HOSTDELIM ':' -#define UPDIR ".." -#define UIDSEP '@' -#define NFS_VERSION_2 NFS_VERSION - -/* we use a dynamically assigned major number */ -#define NFS_MAJOR (nfsGlob.nfs_major) - - -/* NOTE: RTEMS (ss-20020301) uses a 'short st_ino' type :-( but the - * NFS fileid is 32 bit. - * As a workarount, we merge the upper 16bits of the fileid into the - * minor device no. Hence, it is still possible to uniquely identify - * a file by looking at its device number (major = nfs, minor = part - * of the fileid + our 'nfs-id' identifier). - * - * This has an impact on performance, as e.g. getcwd() stats() all - * directory entries when it believes it has crossed a mount point - * (a.st_dev != b.st_dev). - * - * OTOH, it also might cause node comparison failure! E.g. 'getcwd()' - * assumes that two nodes residing in the same directory must be located - * on the same device and hence compares 'st_ino' only. - * If two files in the same directory have the same inode number - * modulo 2^16, they will be considered equal (although their device - * number doesn't match - getcwd doesn't look at it). - * - * Other software might or might not be affected. - * - * The only clean solution to this problem is bumping up the size of - * 'ino_t' at least to 'long'. - * Note that this requires _all_ software (libraries etc.) to be - * recompiled. - */ - -#define NFS_MAKE_DEV_T_INO_HACK(node) \ - rtems_filesystem_make_dev_t( NFS_MAJOR, \ - (((node)->nfs->id)<<16) | (SERP_ATTR((node)).fileid >> 16) ) - -/* use our 'nfs id' and the server's fsid for the minor device number - * this should be fairly unique - */ -#define NFS_MAKE_DEV_T(node) \ - rtems_filesystem_make_dev_t( NFS_MAJOR, \ - (((node)->nfs->id)<<16) | (SERP_ATTR((node)).fsid & ((1<<16)-1)) ) - -#define DIRENT_HEADER_SIZE ( sizeof(struct dirent) - \ - sizeof( ((struct dirent *)0)->d_name ) ) - - -/* debugging flags */ -#define DEBUG_COUNT_NODES (1<<0) -#define DEBUG_TRACK_NODES (1<<1) -#define DEBUG_EVALPATH (1<<2) -#define DEBUG_READDIR (1<<3) -#define DEBUG_SYSCALLS (1<<4) - -/* #define DEBUG ( DEBUG_SYSCALLS | DEBUG_COUNT_NODES ) */ - -#ifdef DEBUG -#define STATIC -#else -#define STATIC static -#endif - -#define MUTEX_ATTRIBUTES (RTEMS_LOCAL | \ - RTEMS_PRIORITY | \ - RTEMS_INHERIT_PRIORITY | \ - RTEMS_BINARY_SEMAPHORE) - -#define LOCK(s) do { rtems_semaphore_obtain((s), \ - RTEMS_WAIT, \ - RTEMS_NO_TIMEOUT); \ - } while (0) - -#define UNLOCK(s) do { rtems_semaphore_release((s)); \ - } while (0) - -/***************************************** - Types with Associated XDR Routines - *****************************************/ - -/* a string buffer with a maximal length. - * If the buffer pointer is NULL, it is updated - * with an appropriately allocated area. - */ -typedef struct strbuf { - char *buf; - u_int max; -} strbuf; - -static bool_t -xdr_strbuf(XDR *xdrs, strbuf *obj) -{ - return xdr_string(xdrs, &obj->buf, obj->max); -} - -/* Read 'readlink' results into a 'strbuf'. - * This is convenient as it avoids - * one extra step of copying / lenght - * checking. - */ -typedef struct readlinkres_strbuf { - nfsstat status; - strbuf strbuf; -} readlinkres_strbuf; - -static bool_t -xdr_readlinkres_strbuf(XDR *xdrs, readlinkres_strbuf *objp) -{ - if ( !xdr_nfsstat(xdrs, &objp->status) ) - return FALSE; - - if ( NFS_OK == objp->status ) { - if ( !xdr_string(xdrs, &objp->strbuf.buf, objp->strbuf.max) ) - return FALSE; - } - return TRUE; -} - - -/* DirInfoRec is used instead of dirresargs - * to convert recursion into iteration. The - * 'rpcgen'erated xdr_dirresargs ends up - * doing nested calls when unpacking the - * 'next' pointers. - */ - -typedef struct DirInfoRec_ { - readdirargs readdirargs; - /* clone of the 'readdirres' fields; - * the cookie is put into the readdirargs above - */ - nfsstat status; - char *buf, *ptr; - int len; - bool_t eofreached; -} DirInfoRec, *DirInfo; - -/* this deals with one entry / record */ -static bool_t -xdr_dir_info_entry(XDR *xdrs, DirInfo di) -{ -union { - char nambuf[NFS_MAXNAMLEN+1]; - nfscookie cookie; -} dummy; -struct dirent *pde = (struct dirent *)di->ptr; -u_int fileid; -char *name; -register int nlen = 0,len,naligned = 0; -nfscookie *pcookie; - - len = di->len; - - if ( !xdr_u_int(xdrs, &fileid) ) - return FALSE; - - /* we must pass the address of a char* */ - name = (len > NFS_MAXNAMLEN) ? pde->d_name : dummy.nambuf; - - if ( !xdr_filename(xdrs, &name) ) { - return FALSE; - } - - if (len >= 0) { - nlen = strlen(name); - naligned = nlen + 1 /* string delimiter */ + 3 /* alignment */; - naligned &= ~3; - len -= naligned; - } - - /* if the cookie goes into the DirInfo, we hope this doesn't fail - * - the caller ends up with an invalid readdirargs cookie otherwise... - */ - pcookie = (len >= 0) ? &di->readdirargs.cookie : &dummy.cookie; - if ( !xdr_nfscookie(xdrs, pcookie) ) { - return FALSE; - } - - di->len = len; - /* adjust the buffer pointer */ - if (len >= 0) { - pde->d_ino = fileid; - pde->d_namlen = nlen; - pde->d_off = di->ptr - di->buf; - if (name == dummy.nambuf) { - memcpy(pde->d_name, dummy.nambuf, nlen + 1); - } - pde->d_reclen = DIRENT_HEADER_SIZE + naligned; - di->ptr += pde->d_reclen; - } - - return TRUE; -} - -/* this routine loops over all entries */ -static bool_t -xdr_dir_info(XDR *xdrs, DirInfo di) -{ -DirInfo dip; - - if ( !xdr_nfsstat(xdrs, &di->status) ) - return FALSE; - - if ( NFS_OK != di->status ) - return TRUE; - - dip = di; - - while (dip) { - /* reserve space for the dirent 'header' - we assume it's word aligned! */ -#ifdef DEBUG - assert( DIRENT_HEADER_SIZE % 4 == 0 ); -#endif - dip->len -= DIRENT_HEADER_SIZE; - - /* we pass a 0 size - size is unused since - * we always pass a non-NULL pointer - */ - if ( !xdr_pointer(xdrs, (caddr_t*)&dip, 0 /* size */, xdr_dir_info_entry) ) - return FALSE; - } - - if ( ! xdr_bool(xdrs, &di->eofreached) ) - return FALSE; - - /* if everything fits into the XDR buffer but not the user's buffer, - * they must resume reading from where xdr_dir_info_entry() started - * skipping and 'eofreached' needs to be adjusted - */ - if ( di->len < 0 && di->eofreached ) - di->eofreached = FALSE; - - return TRUE; -} - - -/* a type better suited for node operations - * than diropres. - * fattr and fhs are swapped so parts of this - * structure may be used as a diroparg which - * is practical when looking up paths. - */ - -/* Macro for accessing serporid fields - */ -#define SERP_ARGS(node) ((node)->serporid.serporid_u.serporid.arg_u) -#define SERP_ATTR(node) ((node)->serporid.serporid_u.serporid.attributes) -#define SERP_FILE(node) ((node)->serporid.serporid_u.serporid.file) - - -typedef struct serporidok { - fattr attributes; - nfs_fh file; - union { - struct { - filename name; - } diroparg; - struct { - sattr attributes; - } sattrarg; - struct { - u_int offset; - u_int count; - u_int totalcount; - } readarg; - struct { - u_int beginoffset; - u_int offset; - u_int totalcount; - struct { - u_int data_len; - char* data_val; - } data; - } writearg; - struct { - filename name; - sattr attributes; - } createarg; - struct { - filename name; - diropargs to; - } renamearg; - struct { - diropargs to; - } linkarg; - struct { - filename name; - nfspath to; - sattr attributes; - } symlinkarg; - struct { - nfscookie cookie; - u_int count; - } readdirarg; - } arg_u; -} serporidok; - -typedef struct serporid { - nfsstat status; - union { - serporidok serporid; - } serporid_u; -} serporid; - -/* an XDR routine to encode/decode the inverted diropres - * into an nfsnodestat; - * - * NOTE: this routine only acts on - * - 'serporid.status' - * - 'serporid.file' - * - 'serporid.attributes' - * and leaves the 'arg_u' alone. - * - * The idea is that a 'diropres' is read into 'serporid' - * which can then be used as an argument to subsequent - * NFS-RPCs (after filling in the node's arg_u). - */ -static bool_t -xdr_serporidok(XDR *xdrs, serporidok *objp) -{ - if (!xdr_nfs_fh (xdrs, &objp->file)) - return FALSE; - if (!xdr_fattr (xdrs, &objp->attributes)) - return FALSE; - return TRUE; -} - -static bool_t -xdr_serporid(XDR *xdrs, serporid *objp) -{ - if (!xdr_nfsstat (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS_OK: - if (!xdr_serporidok(xdrs, &objp->serporid_u.serporid)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -/***************************************** - Data Structures and Types - *****************************************/ - -/* 'time()' hack with less overhead; */ - -/* assume reading a long word is atomic */ -#define READ_LONG_IS_ATOMIC - -typedef rtems_unsigned32 TimeStamp; - -static inline TimeStamp -nowSeconds(void) -{ -register rtems_unsigned32 rval; -#ifndef READ_LONG_IS_ATOMIC -rtems_interrupt_level l; - - rtems_interrupt_disable(level); -#endif - - rval = _TOD_Seconds_since_epoch; - -#ifndef READ_LONG_IS_ATOMIC - rtems_interrupt_enable(level); -#endif - return rval; -} - - -/* Per mounted FS structure */ -typedef struct NfsRec_ { - /* the NFS server we're talking to. - */ - RpcUdpServer server; - /* statistics; how many NfsNodes are - * currently alive. - */ - int nodesInUse; -#if DEBUG & DEBUG_COUNT_NODES - /* statistics; how many 'NfsNode.str' - * strings are currently allocated. - */ - int stringsInUse; -#endif - /* A small number who uniquely - * identifies a mounted NFS within - * this driver (i.e. this NfsRec). - * Each time a NFS is mounted, the - * global ID counter is incremented - * and its value is assigned to the - * newly created NfsRec. - */ - u_short id; - /* Our RTEMS filesystem mt_entry - */ - rtems_filesystem_mount_table_entry_t *mt_entry; - /* Next NfsRec on a linked list who - * is anchored at nfsGlob - */ - struct NfsRec_ *next; - /* Who we pretend we are - */ - u_long uid,gid; -} NfsRec, *Nfs; - -typedef struct NfsNodeRec_ { - /* This holds this node's attributes - * (stats) and its nfs filehandle. - * It also contains room for nfs rpc - * arguments. - */ - serporid serporid; - /* The arguments we used when doing - * the 'lookup' call for this node. - * We need this information (especially - * the directory FH) for performing - * certain operations on this - * node (in particular: for unlinking - * it from a parent directory) - */ - diropargs args; - /* FS this node belongs to - */ - Nfs nfs; - /* A buffer for the string the - * args.name points to. - * We need this because args.name might - * temporarily point to strings on the - * stack. Duplicates are allocated from - * the heap and attached to 'str' so - * they can be released as appropriate. - */ - char *str; - /* A timestamp for the stats - */ - TimeStamp age; -} NfsNodeRec, *NfsNode; - -/***************************************** - Forward Declarations - *****************************************/ - -static int nfs_readlink( - rtems_filesystem_location_info_t *loc, /* IN */ - char *buf, /* OUT */ - size_t len -); - -static int updateAttr(NfsNode node, int force); - -/* Mask bits when setting attributes. - * Only the 'arg' fields with their - * corresponding bit set in the mask - * will be used. The others are left - * unchanged. - * The 'TOUCH' bits instruct nfs_sattr() - * to update the respective time - * fields to the current time - */ -#define SATTR_MODE (1<<0) -#define SATTR_UID (1<<1) -#define SATTR_GID (1<<2) -#define SATTR_SIZE (1<<3) -#define SATTR_ATIME (1<<4) -#define SATTR_TOUCHA (1<<5) -#define SATTR_MTIME (1<<6) -#define SATTR_TOUCHM (1<<7) -#define SATTR_TOUCH (SATTR_TOUCHM | SATTR_TOUCHA) - -static int -nfs_sattr(NfsNode node, sattr *arg, u_long mask); - -extern struct _rtems_filesystem_operations_table nfs_fs_ops; -extern struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers; -extern struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers; -extern struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers; -extern rtems_driver_address_table drvNfs; - -int -nfsMountsShow(FILE*); - -rtems_status_code -rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc); - - -/***************************************** - Inline Routines - *****************************************/ - - -/* * * * * * * * * * * * * * * * * * - Trivial Operations on a NfsNode - * * * * * * * * * * * * * * * * * */ - -/* determine if a location 'l' is an NFS root node */ -static inline int -locIsRoot(rtems_filesystem_location_info_t *l) -{ -NfsNode me = (NfsNode) l->node_access; -NfsNode r; - r = (NfsNode)l->mt_entry->mt_fs_root.node_access; - return SERP_ATTR(r).fileid == SERP_ATTR(me).fileid && - SERP_ATTR(r).fsid == SERP_ATTR(me).fsid; -} - -/* determine if a location 'l' is an NFS node */ -static inline int -locIsNfs(rtems_filesystem_location_info_t *l) -{ - return l->ops == &nfs_fs_ops; -} - -/* determine if two locations refer to the - * same entity. We know that 'nfsloc' is a - * location inside nfs. However, we needn't - * know anything about 'anyloc'. - */ -static inline int -locAreEqual( - rtems_filesystem_location_info_t *nfsloc, - rtems_filesystem_location_info_t *anyloc -) -{ -NfsNode na = (NfsNode) nfsloc->node_access; -NfsNode nb; - - if (!locIsNfs(anyloc)) - return 0; - - nb = (NfsNode) anyloc->node_access; - - if (na->nfs != nb->nfs) - return 0; - - updateAttr(nb, 0); - - return SERP_ATTR(na).fileid == SERP_ATTR(nb).fileid && - SERP_ATTR(na).fsid == SERP_ATTR(nb).fsid; -} - - - -/***************************************** - Global Variables - *****************************************/ - -/* These are (except for MAXNAMLEN/MAXPATHLEN) copied from IMFS */ - -static rtems_filesystem_limits_and_options_t -nfs_limits_and_options = { - 5, /* link_max */ - 6, /* max_canon */ - 7, /* max_input */ - NFS_MAXNAMLEN, /* name_max */ - NFS_MAXPATHLEN, /* path_max */ - 2, /* pipe_buf */ - 1, /* posix_async_io */ - 2, /* posix_chown_restrictions */ - 3, /* posix_no_trunc */ - 4, /* posix_prio_io */ - 5, /* posix_sync_io */ - 6 /* posix_vdisable */ -}; - -/* size of an encoded 'entry' object */ -static int dirres_entry_size; - -/* Global stuff and statistics */ -static struct nfsstats { - /* A lock for protecting the - * linked ist of mounted NFS - * and the num_mounted_fs field - */ - rtems_id llock; - /* A lock for protecting misc - * stuff within the driver. - * The lock must only be held - * for short periods of time. - */ - rtems_id lock; - /* Our major number as assigned - * by RTEMS - */ - rtems_device_major_number nfs_major; - /* The number of currently - * mounted NFS - */ - int num_mounted_fs; - /* A list of the currently - * mounted NFS - */ - struct NfsRec_ *mounted_fs; - /* A counter for allocating - * unique IDs to each mounted - * NFS. - * Assume we are not going to - * do more than 16k mounts - * during the system lifetime - */ - u_short fs_ids; -} nfsGlob = {0/* IMPORTANT */}; - - -/* Two pools of RPC transactions; - * One with small send buffers - * the other with a big one. - * The actual size of the small - * buffer is configurable (see top). - * - * Note: The RX buffers are always - * big - */ -static RpcUdpXactPool smallPool = 0; -static RpcUdpXactPool bigPool = 0; - - -/***************************************** - Implementation - *****************************************/ - -/* Create a Nfs object. This is - * per-mounted NFS information. - * - * ARGS: The Nfs server handle. - * - * RETURNS: Nfs on success, - * NULL on failure with - * errno set - * - * NOTE: The submitted server - * object is 'owned' by - * this Nfs and will be - * destroyed by nfsDestroy() - */ -static Nfs -nfsCreate(RpcUdpServer server) -{ -Nfs rval = calloc(1,sizeof(*rval)); - - if (rval) { - rval->server = server; - LOCK(nfsGlob.llock); - rval->next = nfsGlob.mounted_fs; - nfsGlob.mounted_fs = rval; - UNLOCK(nfsGlob.llock); - } else { - errno = ENOMEM; - } - return rval; -} - -/* Destroy an Nfs object and - * its associated server - */ -static void -nfsDestroy(Nfs nfs) -{ -register Nfs prev; - if (!nfs) - return; - - LOCK(nfsGlob.llock); - if (nfs == nfsGlob.mounted_fs) - nfsGlob.mounted_fs = nfs->next; - else { - for (prev = nfsGlob.mounted_fs; - prev && prev->next != nfs; - prev = prev->next) - /* nothing else to do */; - assert( prev ); - prev->next = nfs->next; - } - UNLOCK(nfsGlob.llock); - - nfs->next = 0; /* paranoia */ - rpcUdpServerDestroy(nfs->server); - free(nfs); -} - -/* - * Create a Node. The node will - * be associated with a particular - * mounted NFS identified by 'nfs' - * Optionally, a NFS file handle - * may be copied into this node. - * - * ARGS: nfs of the NFS this node - * belongs to. - * NFS file handle identifying - * this node. - * RETURNS: node on success, - * NULL on failure with errno - * set. - * - * NOTE: The caller of this routine - * is responsible for copying - * a NFS file handle if she - * choses to pass a NULL fh. - * - * The driver code assumes the - * a node always has a valid - * NFS filehandle and file - * attributes (unless the latter - * are aged). - */ -static NfsNode -nfsNodeCreate(Nfs nfs, nfs_fh *fh) -{ -NfsNode rval = malloc(sizeof(*rval)); - -#if DEBUG & DEBUG_TRACK_NODES - fprintf(stderr,"NFS: creating a node\n"); -#endif - - if (rval) { - if (fh) - memcpy( &SERP_FILE(rval), fh, sizeof(*fh) ); - rval->nfs = nfs; - rval->str = 0; - LOCK(nfsGlob.lock); - nfs->nodesInUse++; - UNLOCK(nfsGlob.lock); - } else { - errno = ENOMEM; - } - - return rval; -} - -/* destroy a node */ -static void -nfsNodeDestroy(NfsNode node) -{ -#if DEBUG & DEBUG_TRACK_NODES - fprintf(stderr,"NFS: destroying a node\n"); -#endif -#if 0 - if (!node) - return; - /* this probably does nothing... */ - xdr_free(xdr_serporid, &node->serporid); -#endif - - LOCK(nfsGlob.lock); - node->nfs->nodesInUse--; -#if DEBUG & DEBUG_COUNT_NODES - if (node->str) - node->nfs->stringsInUse--; -#endif - UNLOCK(nfsGlob.lock); - - if (node->str) - free(node->str); - - free(node); -} - -/* Clone a given node (AKA copy constructor), - * i.e. create an exact copy. - * - * ARGS: node to clone - * RETURNS: new node on success - * NULL on failure with errno set. - * - * NOTE: a string attached to 'str' - * is cloned as well. Outdated - * attributes (of the new copy - * only) will be refreshed - * (if unsuccessful, this could - * be a reason for failure to - * clone a node). - */ -static NfsNode -nfsNodeClone(NfsNode node) -{ -NfsNode rval = nfsNodeCreate(node->nfs, 0); - - if (rval) { - *rval = *node; - - /* must clone the string also */ - if (node->str) { - rval->args.name = rval->str = strdup(node->str); - if (!rval->str) { - nfsNodeDestroy(rval); - return 0; - } -#if DEBUG & DEBUG_COUNT_NODES - LOCK(nfsGlob.lock); - node->nfs->stringsInUse++; - UNLOCK(nfsGlob.lock); -#endif - } - - /* possibly update the stats */ - if (updateAttr(rval, 0 /* only if necessary */)) { - nfsNodeDestroy(rval); - return 0; - } - } - return rval; -} - -/* Initialize the driver. - * - * ARGS: depth of the small and big - * transaction pools, i.e. how - * many transactions (buffers) - * should always be kept around. - * - * (If more transactions are needed, - * they are created and destroyed - * on the fly). - */ -void -nfsInit(int smallPoolDepth, int bigPoolDepth) -{ -entry dummy; - - fprintf(stderr,"This is RTEMS-NFS Release $Name$\n"); - fprintf(stderr,"($Id$)\n\n"); - fprintf(stderr,"Till Straumann, Stanford/SLAC/SSRL 2002\n"); - fprintf(stderr,"See LICENSE file for licensing info\n"); - - /* Get a major number */ - - if (RTEMS_SUCCESSFUL != rtems_io_register_driver(0, &drvNfs, &nfsGlob.nfs_major)) { - fprintf(stderr,"Registering NFS driver failed - %s\n", strerror(errno)); - return; - } - - if (0==smallPoolDepth) - smallPoolDepth = 20; - if (0==bigPoolDepth) - bigPoolDepth = 10; - - /* it's crucial to zero out the 'next' pointer - * because it terminates the xdr_entry recursion - * - * we also must make the filename some non-zero - * char pointer! - */ - - memset(&dummy, 0, sizeof(dummy)); - - dummy.nextentry = 0; - dummy.name = "somename"; /* guess average length of a filename */ - dirres_entry_size = xdr_sizeof(xdr_entry, &dummy); - - assert( smallPool = rpcUdpXactPoolCreate( - NFS_PROGRAM, - NFS_VERSION_2, - CONFIG_NFS_SMALL_XACT_SIZE, - smallPoolDepth) ); - - assert( bigPool = rpcUdpXactPoolCreate( - NFS_PROGRAM, - NFS_VERSION_2, - CONFIG_NFS_BIG_XACT_SIZE, - bigPoolDepth) ); - - assert( RTEMS_SUCCESSFUL == rtems_semaphore_create( - rtems_build_name('N','F','S','l'), - 1, - MUTEX_ATTRIBUTES, - 0, - &nfsGlob.llock) ); - - assert( RTEMS_SUCCESSFUL == rtems_semaphore_create( - rtems_build_name('N','F','S','m'), - 1, - MUTEX_ATTRIBUTES, - 0, - &nfsGlob.lock) ); - - if (sizeof(ino_t) < sizeof(u_int)) { - fprintf(stderr, - "WARNING: Using 'short st_ino' hits performance and may fail to access/find correct files\n"); - fprintf(stderr, - "you should fix newlib's sys/stat.h - for now I'll enable a hack...\n"); - - } -} - -/* Driver cleanup code - */ -int -nfsCleanup(void) -{ -rtems_id l; -int refuse; - - if (!nfsGlob.llock) { - /* registering the driver failed - let them still cleanup */ - return 0; - } - - LOCK(nfsGlob.llock); - if ( (refuse = nfsGlob.num_mounted_fs) ) { - fprintf(stderr,"Refuse to unload NFS; %i filesystems still mounted.\n", - refuse); - nfsMountsShow(stderr); - /* yes, printing is slow - but since you try to unload the driver, - * you assume nobody is using NFS, so what if they have to wait? - */ - UNLOCK(nfsGlob.llock); - return -1; - } - - rtems_semaphore_delete(nfsGlob.lock); - nfsGlob.lock = 0; - - /* hold the lock while cleaning up... */ - - rpcUdpXactPoolDestroy(smallPool); - rpcUdpXactPoolDestroy(bigPool); - l = nfsGlob.llock; - rtems_io_unregister_driver(nfsGlob.nfs_major); - - rtems_semaphore_delete(l); - nfsGlob.llock = 0; - return 0; -} - -/* NFS RPC wrapper. - * - * ARGS: srvr the NFS server we want to call - * proc the NFSPROC_xx we want to invoke - * xargs xdr routine to wrap the arguments - * pargs pointer to the argument object - * xres xdr routine to unwrap the results - * pres pointer to the result object - * - * RETURNS: 0 on success, -1 on error with errno set. - * - * NOTE: the caller assumes that errno is set to - * a nonzero value if this routine returns - * an error (nonzero return value). - * - * This routine prints RPC error messages to - * stderr. - */ -STATIC int -nfscall( - RpcUdpServer srvr, - int proc, - xdrproc_t xargs, - void * pargs, - xdrproc_t xres, - void * pres) -{ -RpcUdpXact xact; -enum clnt_stat stat; -RpcUdpXactPool pool; -int rval = -1; - - - switch (proc) { - case NFSPROC_SYMLINK: - case NFSPROC_WRITE: - pool = bigPool; break; - default: pool = smallPool; break; - } - - xact = rpcUdpXactPoolGet(pool, XactGetCreate); - - if ( !xact ) { - errno = ENOMEM; - return -1; - } - - if ( RPC_SUCCESS != (stat=rpcUdpSend( - xact, - srvr, - NFSCALL_TIMEOUT, - proc, - xres, - pres, - xargs, - pargs, - 0)) || - RPC_SUCCESS != (stat=rpcUdpRcv(xact)) ) { - - fprintf(stderr, - "NFS (proc %i) - %s\n", - proc, - clnt_sperrno(stat)); - - switch (stat) { - /* TODO: this is probably not complete and/or fully accurate */ - case RPC_CANTENCODEARGS : errno = EINVAL; break; - case RPC_AUTHERROR : errno = EPERM; break; - - case RPC_CANTSEND : - case RPC_CANTRECV : /* hope they have errno set */ - case RPC_SYSTEMERROR : break; - - default : errno = EIO; break; - } - } else { - rval = 0; - } - - /* release the transaction back into the pool */ - rpcUdpXactPoolPut(xact); - - if (rval && !errno) - errno = EIO; - - return rval; -} - -/* Check the 'age' of a node's stats - * and read the attributes from the server - * if necessary. - * - * ARGS: node node to update - * force enforce updating ignoring - * the timestamp/age - * - * RETURNS: 0 on success, - * -1 on failure with errno set - */ - -static int -updateAttr(NfsNode node, int force) -{ - - if (force -#ifdef CONFIG_ATTR_LIFETIME - || (nowSeconds() - node->age > CONFIG_ATTR_LIFETIME) -#endif - ) { - if ( nfscall(node->nfs->server, - NFSPROC_GETATTR, - xdr_nfs_fh, &SERP_FILE(node), - xdr_attrstat, &node->serporid) ) - return -1; - - if ( NFS_OK != node->serporid.status ) { - errno = node->serporid.status; - return -1; - } - - node->age = nowSeconds(); - } - - return 0; -} - -/* - * IP address helper. Note that we avoid - * gethostbyname() since it's not reentrant. - * - * initialize a sockaddr_in from a - * ['.''@']':'" string and let - * pPath point to the part; retrieve the optional - * uid/gids - * - * ARGS: see description above - * - * RETURNS: 0 on success, - * -1 on failure with errno set - */ -static int -buildIpAddr(u_long *puid, u_long *pgid, - char **pHost, struct sockaddr_in *psa, - char **pPath) -{ -char host[30]; -char *chpt = *pPath; -char *path; -int len; - - if ( !chpt ) { - errno = EINVAL; - return -1; - } - - /* look for the optional uid/gid */ - if ( (chpt = strchr(chpt, UIDSEP)) ) { - if ( 2 != sscanf(*pPath,"%li.%li",puid,pgid) ) { - errno = EINVAL; - return -1; - } - chpt++; - } else { - *puid = RPCIOD_DEFAULT_ID; - *pgid = RPCIOD_DEFAULT_ID; - chpt = *pPath; - } - if ( pHost ) - *pHost = chpt; - - /* split the device name which is in the form - * - * ':' - * - * into its components using a local buffer - */ - - if ( !(path = strchr(chpt, HOSTDELIM)) || - (len = path - chpt) >= sizeof(host) - 1 ) { - errno = EINVAL; - return -1; - } - /* point to path beyond ':' */ - path++; - - strncpy(host, chpt, len); - host[len]=0; - - if ( ! inet_aton(host, &psa->sin_addr) ) { - errno = ENXIO; - return -1; - } - - psa->sin_family = AF_INET; - psa->sin_port = 0; - *pPath = path; - return 0; -} - -/* wrapper similar to nfscall. - * However, since it is not used - * very often, the simpler and less - * efficient rpcUdpCallRp API is used. - * - * ARGS: see 'nfscall()' above - * - * RETURNS: RPC status - */ -static enum clnt_stat -mntcall( - struct sockaddr_in *psrvr, - int proc, - xdrproc_t xargs, - void * pargs, - xdrproc_t xres, - void * pres, - u_long uid, - u_long gid) -{ -#ifdef MOUNT_V1_PORT -int retry; -#endif -enum clnt_stat stat = RPC_FAILED; - -#ifdef MOUNT_V1_PORT - /* if the portmapper fails, retry a fixed port */ - for (retry = 1, psrvr->sin_port = 0, stat = RPC_FAILED; - retry >= 0 && stat; - stat && (psrvr->sin_port = htons(MOUNT_V1_PORT)), retry-- ) -#endif - stat = rpcUdpCallRp( - psrvr, - MOUNTPROG, - MOUNTVERS, - proc, - xargs, - pargs, - xres, - pres, - uid, - gid, - MNTCALL_TIMEOUT - ); - return stat; -} - -/***************************************** - RTEMS File System Operations for NFS - *****************************************/ - -#if 0 /* for reference */ - -struct rtems_filesystem_location_info_tt -{ - void *node_access; - rtems_filesystem_file_handlers_r *handlers; - rtems_filesystem_operations_table *ops; - rtems_filesystem_mount_table_entry_t *mt_entry; -}; - -#endif - -/* - * Evaluate a path letting 'pathloc' travel along. - * - * The important semantics of this operation are: - * - * If this routine returns -1, the caller assumes - * pathloc to be _invalid_ and hence it will not - * invoke rtems_filesystem_freenode() on it. - * - * OTOH, if evalpath returns 0, - * rtems_filesystem_freenode() will eventually be - * called which results in our freeing the associated - * NfsNode attached to node_access. - * - * Therefore, this routine will _always_ allocate - * a NfsNode and pass it out to *pathloc (provided - * that the evaluation succeeds). - * - * However, if the evaluation finds that it has to - * step across FS boundaries (mount point or a symlink - * pointing outside), the NfsNode is destroyed - * before passing control to the new FS' evalpath_h() - * - */ - -STATIC int nfs_do_evalpath( - const char *pathname, /* IN */ - void *arg, - rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ - int forMake -) -{ -char *del = 0, *part; -int e = 0; -NfsNode node = pathloc->node_access; -char *p = malloc(MAXPATHLEN+1); -Nfs nfs = (Nfs)pathloc->mt_entry->fs_info; -RpcUdpServer server = nfs->server; - - if ( !p ) { - e = ENOMEM; - goto cleanup; - } - strcpy(p, pathname); - - /* clone the node */ - if ( !(node = nfsNodeClone(node)) ) { - /* nodeClone sets errno */ - goto cleanup; - } - - pathloc->node_access = node; - - for (part=p; part && *part; part=del) { - - if ( NFLNK == SERP_ATTR(node).type ) { - /* follow midpath link */ - char *b = malloc(NFS_MAXPATHLEN+1); - int l; - - if (!b) { - e = ENOMEM; - goto cleanup; - } - if (nfs_readlink(pathloc, b, NFS_MAXPATHLEN+1)) { - free(b); - e = errno; - goto cleanup; - } - - /* prepend the link value to the rest of the path */ - if ( (l=strlen(b)) + strlen(part) + 1 > NFS_MAXPATHLEN ) { - free(b); - e = EINVAL; - goto cleanup; - } - /* swap string buffers and reset delimiter */ - b[l++] = DELIM; - strcpy(b+l,part); - part = b; - b = p; - p = del = part; - - free(b); - - /* back up the directory filehandle (only necessary - * if we don't back out to the root - */ - if (! (DELIM == *part) ) { - memcpy( &SERP_FILE(node), - &node->args.dir, - sizeof(node->args.dir)); - - if (updateAttr(node, 1 /* force */)) { - e = errno; - goto cleanup; - } - } - } - - /* find delimiter and eat /// sequences - * (only if we don't restart at the root) - */ - if ( DELIM != *part && (del = strchr(part, DELIM))) { - do { - *del++=0; - } while (DELIM==*del); - } - - /* refuse to backup over the root */ - if ( 0==strcmp(part,UPDIR) - && locAreEqual(pathloc, &rtems_filesystem_root) ) { - part++; - } - - /* cross mountpoint upwards */ - if ( (0==strcmp(part,UPDIR) && locIsRoot(pathloc)) /* cross mountpoint up */ - || DELIM == *part /* link starts at root */ - ) { - int rval; - -#if DEBUG & DEBUG_EVALPATH - fprintf(stderr, - "Crossing mountpoint upwards\n"); -#endif - - if (DELIM == *part) { - *pathloc = rtems_filesystem_root; - } else { - *pathloc = pathloc->mt_entry->mt_point_node; - /* re-append the rest of the path */ - if (del) - while ( 0 == *--del ) - *del = DELIM; - } - - nfsNodeDestroy(node); - -#if DEBUG & DEBUG_EVALPATH - fprintf(stderr, - "Re-evaluating '%s'\n", - part); -#endif - - if (forMake) - rval = pathloc->ops->evalformake_h(part, pathloc, (const char**)arg); - else - rval = pathloc->ops->evalpath_h(part, (int)arg, pathloc); - - free(p); - return rval; - } - - /* lookup one element */ - SERP_ARGS(node).diroparg.name = part; - - /* remember args / directory fh */ - memcpy( &node->args, &SERP_FILE(node), sizeof(node->args)); - - /* don't lookup the item we want to create */ - if ( forMake && (!del || !*del) ) - break; - -#if DEBUG & DEBUG_EVALPATH - fprintf(stderr,"Looking up '%s'\n",part); -#endif - - if ( nfscall(server, - NFSPROC_LOOKUP, - xdr_diropargs, &SERP_FILE(node), - xdr_serporid, &node->serporid) || - NFS_OK != (errno=node->serporid.status) ) { - e = errno; - goto cleanup; - } - node->age = nowSeconds(); - -#if DEBUG & DEBUG_EVALPATH - if (NFLNK == SERP_ATTR(node).type && del) { - fprintf(stderr, - "Following midpath link '%s'\n", - part); - } -#endif - - } - - if (forMake) { - /* remember the name - do this _before_ copying - * the name to local storage; the caller expects a - * pointer into pathloc - */ - assert( node->args.name ); - - *(const char**)arg = pathname + (node->args.name - p); - -#if 0 - /* restore the directory node */ - - memcpy( &SERP_FILE(node), - &node->args.dir, - sizeof(node->args.dir)); - - if ( (nfscall(nfs->server, - NFSPROC_GETATTR, - xdr_nfs_fh, &SERP_FILE(node), - xdr_attrstat, &node->serporid) && !errno && (errno = EIO)) || - (NFS_OK != (errno=node->serporid.status) ) ) { - goto cleanup; - } -#endif - } - - if (locIsRoot(pathloc)) { - - /* stupid filesystem code has no 'op' for comparing nodes - * but just compares the 'node_access' pointers. - * Luckily, this is only done for comparing the root nodes. - * Hence, we never give them a copy of the root but always - * the root itself. - */ - pathloc->node_access = pathloc->mt_entry->mt_fs_root.node_access; - /* increment the 'in use' counter since we return one more - * reference to the root node - */ - LOCK(nfsGlob.lock); - nfs->nodesInUse++; - UNLOCK(nfsGlob.lock); - nfsNodeDestroy(node); - - - } else { - switch (SERP_ATTR(node).type) { - case NFDIR: pathloc->handlers = &nfs_dir_file_handlers; break; - case NFREG: pathloc->handlers = &nfs_file_file_handlers; break; - case NFLNK: pathloc->handlers = &nfs_link_file_handlers; break; - default: pathloc->handlers = &rtems_filesystem_null_handlers; break; - } - pathloc->node_access = node; - - /* remember the name of this directory entry */ - - if (node->args.name) { - if (node->str) { -#if DEBUG & DEBUG_COUNT_NODES - LOCK(nfsGlob.lock); - nfs->stringsInUse--; - UNLOCK(nfsGlob.lock); -#endif - free(node->str); - } - node->args.name = node->str = strdup(node->args.name); - if (!node->str) { - e = ENOMEM; - goto cleanup; - } - -#if DEBUG & DEBUG_COUNT_NODES - LOCK(nfsGlob.lock); - nfs->stringsInUse++; - UNLOCK(nfsGlob.lock); -#endif - } - - } - node = 0; - - e = 0; - -cleanup: - free(p); - if (node) { - nfsNodeDestroy(node); - pathloc->node_access = 0; - } -#if DEBUG & DEBUG_COUNT_NODES - fprintf(stderr, - "leaving evalpath, in use count is %i nodes, %i strings\n", - nfs->nodesInUse, nfs->stringsInUse); -#endif - if (e) { -#if DEBUG & DEBUG_EVALPATH - perror("Evalpath"); -#endif - rtems_set_errno_and_return_minus_one(e); - } else { - return 0; - } -} - -/* MANDATORY; may set errno=ENOSYS and return -1 */ -static int nfs_evalformake( - const char *path, /* IN */ - rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ - const char **pname /* OUT */ -) -{ - return nfs_do_evalpath(path, (void*)pname, pathloc, 1 /*forMake*/); -} - -static int nfs_evalpath( - const char *path, /* IN */ - int flags, /* IN */ - rtems_filesystem_location_info_t *pathloc /* IN/OUT */ -) -{ - return nfs_do_evalpath(path, (void*)flags, pathloc, 0 /*not forMake*/); -} - - -/* create a hard link */ - -static int nfs_link( - rtems_filesystem_location_info_t *to_loc, /* IN */ - rtems_filesystem_location_info_t *parent_loc, /* IN */ - const char *name /* IN */ -) -{ -NfsNode pNode; -nfsstat status; -NfsNode tNode = to_loc->node_access; - -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr,"Creating link '%s'\n",name); -#endif - - if ( !locIsNfs(parent_loc) ) { - errno = EXDEV; - return -1; - } - - pNode = parent_loc->node_access; - if ( tNode->nfs != pNode->nfs ) { - errno = EXDEV; - return -1; - } - memcpy(&SERP_ARGS(tNode).linkarg.to.dir, - &SERP_FILE(pNode), - sizeof(SERP_FILE(pNode))); - - SERP_ARGS(tNode).linkarg.to.name = (filename)name; - - if ( nfscall(tNode->nfs->server, - NFSPROC_LINK, - xdr_linkargs, &SERP_FILE(tNode), - xdr_nfsstat, &status) - || (NFS_OK != (errno = status)) - ) { -#if DEBUG & DEBUG_SYSCALLS - perror("nfs_link"); -#endif - return -1; - } - - return 0; - -} - -static int nfs_do_unlink( - rtems_filesystem_location_info_t *loc, /* IN */ - int proc -) -{ -nfsstat status; -NfsNode node = loc->node_access; -Nfs nfs = node->nfs; -#if DEBUG & DEBUG_SYSCALLS -char *name = NFSPROC_REMOVE == proc ? - "nfs_unlink" : "nfs_rmdir"; -#endif - - /* The FS generics have determined that pathloc is _not_ - * a directory. Hence we may assume that the parent - * is in our NFS. - */ - -#if DEBUG & DEBUG_SYSCALLS - assert( node->args.name == node->str && node->str ); - - fprintf(stderr,"%s '%s'\n", name, node->args.name); -#endif - - if ( nfscall(nfs->server, - proc, - xdr_diropargs, &node->args, - xdr_nfsstat, &status) - || (NFS_OK != (errno = status)) - ) { -#if DEBUG & DEBUG_SYSCALLS - perror(name); -#endif - return -1; - } - - return 0; -} - -static int nfs_unlink( - rtems_filesystem_location_info_t *loc /* IN */ -) -{ - return nfs_do_unlink(loc, NFSPROC_REMOVE); -} - -static int nfs_chown( - rtems_filesystem_location_info_t *pathloc, /* IN */ - uid_t owner, /* IN */ - gid_t group /* IN */ -) -{ -sattr arg; - - arg.uid = owner; - arg.gid = group; - - return nfs_sattr(pathloc->node_access, &arg, SATTR_UID | SATTR_GID); - -} - -/* Cleanup the FS private info attached to pathloc->node_access */ -static int nfs_freenode( - rtems_filesystem_location_info_t *pathloc /* IN */ -) -{ -Nfs nfs = ((NfsNode)pathloc->node_access)->nfs; - - /* never destroy the root node; it is released by the unmount - * code - */ - if (locIsRoot(pathloc)) { - /* just adjust the references to the root node but - * don't really release it - */ - LOCK(nfsGlob.lock); - nfs->nodesInUse--; - UNLOCK(nfsGlob.lock); - } else { - nfsNodeDestroy(pathloc->node_access); - pathloc->node_access = 0; - } -#if DEBUG & DEBUG_COUNT_NODES - fprintf(stderr, - "leaving freenode, in use count is %i nodes, %i strings\n", - nfs->nodesInUse, - nfs->stringsInUse); -#endif - return 0; -} - -/* NOTE/TODO: mounting on top of NFS is not currently supported - * - * Challenge: stateless protocol. It would be possible to - * delete mount points on the server. We would need some sort - * of a 'garbage collector' looking for dead/unreachable - * mount points and unmounting them. - * Also, the path evaluation routine would have to check - * for crossing mount points. Crossing over from one NFS - * into another NFS could probably handled iteratively - * rather than by recursion. - */ - -#ifdef DECLARE_BODY -/* This routine is called when they try to mount something - * on top of THIS filesystem, i.e. if one of our directories - * is used as a mount point - */ -static int nfs_mount( - rtems_filesystem_mount_table_entry_t *mt_entry /* in */ -)DECLARE_BODY -#else -#define nfs_mount 0 -#endif - -#ifdef DECLARE_BODY -/* This op is called when they try to unmount a FS - * from a mountpoint managed by THIS FS. - */ -static int nfs_unmount( - rtems_filesystem_mount_table_entry_t *mt_entry /* in */ -)DECLARE_BODY -#else -#define nfs_unmount 0 -#endif - -#if 0 - -/* for reference (libio.h) */ - -struct rtems_filesystem_mount_table_entry_tt { - Chain_Node Node; - rtems_filesystem_location_info_t mt_point_node; - rtems_filesystem_location_info_t mt_fs_root; - int options; - void *fs_info; - - rtems_filesystem_limits_and_options_t pathconf_limits_and_options; - - /* - * When someone adds a mounted filesystem on a real device, - * this will need to be used. - * - * The best option long term for this is probably an open file descriptor. - */ - char *dev; -}; -#endif - - -/* This op is called as the last step of mounting this FS */ -STATIC int nfs_fsmount_me( - rtems_filesystem_mount_table_entry_t *mt_entry -) -{ -char *host; -struct sockaddr_in saddr; -enum clnt_stat stat; -fhstatus fhstat; -u_long uid,gid; -#ifdef NFS_V2_PORT -int retry; -#endif -Nfs nfs = 0; -NfsNode rootNode = 0; -RpcUdpServer nfsServer = 0; -int e = -1; -char *path = mt_entry->dev; - - - if ( buildIpAddr(&uid, &gid, &host, &saddr, &path) ) - return -1; - - -#ifdef NFS_V2_PORT - /* if the portmapper fails, retry a fixed port */ - for (retry = 1, saddr.sin_port = 0, stat = RPC_FAILED; - retry >= 0 && stat; - stat && (saddr.sin_port = htons(NFS_V2_PORT)), retry-- ) -#endif - stat = rpcUdpServerCreate( - &saddr, - NFS_PROGRAM, - NFS_VERSION_2, - uid, - gid, - &nfsServer - ); - - if ( RPC_SUCCESS != stat ) { - fprintf(stderr, - "Unable to contact NFS server - invalid port? (%s)\n", - clnt_sperrno(stat)); - e = EPROTONOSUPPORT; - goto cleanup; - } - - - /* first, try to ping the NFS server by - * calling the NULL proc. - */ - if ( nfscall(nfsServer, - NFSPROC_NULL, - xdr_void, 0, - xdr_void, 0) ) { - - fputs("NFS Ping ",stderr); - fwrite(host, 1, path-host-1, stderr); - fprintf(stderr," failed: %s\n", strerror(errno)); - - e = errno ? errno : EIO; - goto cleanup; - } - - /* that seemed to work - we now try the - * actual mount - */ - - /* reuse server address but let the mntcall() - * search for the mountd's port - */ - saddr.sin_port = 0; - - stat = mntcall( &saddr, - MOUNTPROC_MNT, - xdr_dirpath, - &path, - xdr_fhstatus, - &fhstat, - uid, - gid ); - - if (stat) { - fprintf(stderr,"MOUNT -- %s\n",clnt_sperrno(stat)); - if ( e<=0 ) - e = EIO; - goto cleanup; - } else if (NFS_OK != (e=fhstat.fhs_status)) { - fprintf(stderr,"MOUNT: %s\n",strerror(e)); - goto cleanup; - } - - assert( nfs = nfsCreate(nfsServer) ); - nfsServer = 0; - - nfs->uid = uid; - nfs->gid = gid; - - /* that seemed to work - we now create the root node - * and we also must obtain the root node attributes - */ - assert( rootNode = nfsNodeCreate(nfs, (nfs_fh*)&fhstat.fhstatus_u.fhs_fhandle ) ); - - if ( updateAttr(rootNode, 1 /* force */) ) { - e = errno; - goto cleanup; - } - - /* looks good so far */ - - mt_entry->mt_fs_root.node_access = rootNode; - - rootNode = 0; - - mt_entry->mt_fs_root.ops = &nfs_fs_ops; - mt_entry->mt_fs_root.handlers = &nfs_dir_file_handlers; - mt_entry->pathconf_limits_and_options = nfs_limits_and_options; - - LOCK(nfsGlob.llock); - nfsGlob.num_mounted_fs++; - /* allocate a new ID for this FS */ - nfs->id = nfsGlob.fs_ids++; - UNLOCK(nfsGlob.llock); - - mt_entry->fs_info = nfs; - nfs->mt_entry = mt_entry; - nfs = 0; - - e = 0; - -cleanup: - if (nfs) - nfsDestroy(nfs); - if (nfsServer) - rpcUdpServerDestroy(nfsServer); - if (rootNode) - nfsNodeDestroy(rootNode); - if (e) - rtems_set_errno_and_return_minus_one(e); - else - return 0; -} - -/* This op is called when they try to unmount THIS fs */ -STATIC int nfs_fsunmount_me( - rtems_filesystem_mount_table_entry_t *mt_entry /* in */ -) -{ -enum clnt_stat stat; -struct sockaddr_in saddr; -char *path = mt_entry->dev; -int nodesInUse; -u_long uid,gid; - - LOCK(nfsGlob.lock); - nodesInUse = ((Nfs)mt_entry->fs_info)->nodesInUse; - UNLOCK(nfsGlob.lock); - - if (nodesInUse > 1 /* one ref to the root node used by us */) { - fprintf(stderr, - "Refuse to unmount; there are still %i nodes in use (1 used by us)\n", - nodesInUse); - rtems_set_errno_and_return_minus_one(EBUSY); - } - - assert( 0 == buildIpAddr(&uid, &gid, 0, &saddr, &path) ); - - stat = mntcall( &saddr, - MOUNTPROC_UMNT, - xdr_dirpath, &path, - xdr_void, 0, - uid, - gid - ); - - if (stat) { - fprintf(stderr,"NFS UMOUNT -- %s\n", clnt_sperrno(stat)); - errno = EIO; - return -1; - } - - nfsNodeDestroy(mt_entry->mt_fs_root.node_access); - mt_entry->mt_fs_root.node_access = 0; - - nfsDestroy(mt_entry->fs_info); - mt_entry->fs_info = 0; - - LOCK(nfsGlob.llock); - nfsGlob.num_mounted_fs--; - UNLOCK(nfsGlob.llock); - - return 0; -} - -/* OPTIONAL; may be NULL - BUT: CAUTION; mount() doesn't check - * for this handler to be present - a fs bug - * //NOTE: (10/25/2002) patch submitted and probably applied - */ -static rtems_filesystem_node_types_t nfs_node_type( - rtems_filesystem_location_info_t *pathloc /* in */ -) -{ -NfsNode node = pathloc->node_access; - - if (updateAttr(node, 0 /* only if old */)) - return -1; - - switch( SERP_ATTR(node).type ) { - default: - /* rtems has no value for 'unknown'; - */ - case NFNON: - case NFSOCK: - case NFBAD: - case NFFIFO: - break; - - - case NFREG: return RTEMS_FILESYSTEM_MEMORY_FILE; - case NFDIR: return RTEMS_FILESYSTEM_DIRECTORY; - - case NFBLK: - case NFCHR: return RTEMS_FILESYSTEM_DEVICE; - - case NFLNK: return RTEMS_FILESYSTEM_SYM_LINK; - } - return -1; -} - -static int nfs_mknod( - const char *path, /* IN */ - mode_t mode, /* IN */ - dev_t dev, /* IN */ - rtems_filesystem_location_info_t *pathloc /* IN/OUT */ -) -{ -rtems_clock_time_value now; -diropres res; -NfsNode node = pathloc->node_access; -mode_t type = S_IFMT & mode; - - if (type != S_IFDIR && type != S_IFREG) - rtems_set_errno_and_return_minus_one(ENOTSUP); - -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr,"nfs_mknod: creating %s\n", path); -#endif - - rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); - - SERP_ARGS(node).createarg.name = (filename)path; - SERP_ARGS(node).createarg.attributes.mode = mode; - /* TODO: either use our uid or use the Nfs credentials */ - SERP_ARGS(node).createarg.attributes.uid = 0; - SERP_ARGS(node).createarg.attributes.gid = 0; - SERP_ARGS(node).createarg.attributes.size = 0; - SERP_ARGS(node).createarg.attributes.atime.seconds = now.seconds; - SERP_ARGS(node).createarg.attributes.atime.useconds = now.microseconds; - SERP_ARGS(node).createarg.attributes.mtime.seconds = now.seconds; - SERP_ARGS(node).createarg.attributes.mtime.useconds = now.microseconds; - - if ( nfscall( node->nfs->server, - NFSPROC_CREATE, - xdr_createargs, &SERP_FILE(node), - xdr_diropres, &res) - || (NFS_OK != (errno = res.status)) ) { -#if DEBUG & DEBUG_SYSCALLS - perror("nfs_mknod"); -#endif - return -1; - } - - return 0; -} - -static int nfs_utime( - rtems_filesystem_location_info_t *pathloc, /* IN */ - time_t actime, /* IN */ - time_t modtime /* IN */ -) -{ -sattr arg; - - /* TODO: add rtems EPOCH - UNIX EPOCH seconds */ - arg.atime.seconds = actime; - arg.atime.useconds = 0; - arg.mtime.seconds = modtime; - arg.mtime.useconds = 0; - - return nfs_sattr(pathloc->node_access, &arg, SATTR_ATIME | SATTR_MTIME); -} - -static int nfs_symlink( - rtems_filesystem_location_info_t *loc, /* IN */ - const char *link_name, /* IN */ - const char *node_name -) -{ -rtems_clock_time_value now; -nfsstat status; -NfsNode node = loc->node_access; - - -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr,"nfs_symlink: creating %s -> %s\n", link_name, node_name); -#endif - - rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); - - SERP_ARGS(node).symlinkarg.name = (filename)link_name; - SERP_ARGS(node).symlinkarg.to = (nfspath) node_name; - - SERP_ARGS(node).symlinkarg.attributes.mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; - /* TODO */ - SERP_ARGS(node).symlinkarg.attributes.uid = 0; - SERP_ARGS(node).symlinkarg.attributes.gid = 0; - SERP_ARGS(node).symlinkarg.attributes.size = 0; - SERP_ARGS(node).symlinkarg.attributes.atime.seconds = now.seconds; - SERP_ARGS(node).symlinkarg.attributes.atime.useconds = now.microseconds; - SERP_ARGS(node).symlinkarg.attributes.mtime.seconds = now.seconds; - SERP_ARGS(node).symlinkarg.attributes.mtime.useconds = now.microseconds; - - if ( nfscall( node->nfs->server, - NFSPROC_SYMLINK, - xdr_symlinkargs, &SERP_FILE(node), - xdr_nfsstat, &status) - || (NFS_OK != (errno = status)) ) { -#if DEBUG & DEBUG_SYSCALLS - perror("nfs_symlink"); -#endif - return -1; - } - - return 0; -} - -static int nfs_do_readlink( - rtems_filesystem_location_info_t *loc, /* IN */ - strbuf *psbuf /* IN/OUT */ -) -{ -NfsNode node = loc->node_access; -Nfs nfs = node->nfs; -readlinkres_strbuf rr; -int wasAlloced; -int rval; - - rr.strbuf = *psbuf; - - wasAlloced = (0 == psbuf->buf); - - if ( (rval = nfscall(nfs->server, - NFSPROC_READLINK, - xdr_nfs_fh, &SERP_FILE(node), - xdr_readlinkres_strbuf, &rr)) ) { - if (wasAlloced) - xdr_free( xdr_strbuf, (caddr_t)&rr.strbuf ); - } - - - if (NFS_OK != rr.status) { - if (wasAlloced) - xdr_free( xdr_strbuf, (caddr_t)&rr.strbuf ); - rtems_set_errno_and_return_minus_one(rr.status); - } - - *psbuf = rr.strbuf; - - return 0; -} - -static int nfs_readlink( - rtems_filesystem_location_info_t *loc, /* IN */ - char *buf, /* OUT */ - size_t len -) -{ -strbuf sbuf; - sbuf.buf = buf; - sbuf.max = len; - - return nfs_do_readlink(loc, &sbuf); -} - -/* The semantics of this routine are: - * - * The caller submits a valid pathloc, i.e. it has - * an NfsNode attached to node_access. - * On return, pathloc points to the target node which - * may or may not be an NFS node. - * Hence, the original NFS node is released in either - * case: - * - link evaluation fails; pathloc points to no valid node - * - link evaluation success; pathloc points to a new valid - * node. If it's an NFS node, a new NfsNode will be attached - * to node_access... - */ - -#define LINKVAL_BUFLEN (MAXPATHLEN+1) -#define RVAL_ERR_BUT_DONT_FREENODE (-1) -#define RVAL_ERR_AND_DO_FREENODE ( 1) -#define RVAL_OK ( 0) - -static int nfs_eval_link( - rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ - int flags /* IN */ -) -{ -rtems_filesystem_node_types_t type; -char *buf = malloc(LINKVAL_BUFLEN); -int rval = RVAL_ERR_AND_DO_FREENODE; - - if (!buf) { - errno = ENOMEM; - goto cleanup; - } - - /* in this loop, we must not use NFS specific ops as we might - * step out of our FS during the process... - * This algorithm should actually be performed by the - * generic's evaluate_path routine :-( - * - * Unfortunately, there is no way of finding the - * directory node who contains 'pathloc', however :-( - */ - do { - /* assume the generics have verified 'pathloc' to be - * a link... - */ - if ( !pathloc->ops->readlink_h ) { - errno = ENOTSUP; - goto cleanup; - } - - if ( pathloc->ops->readlink_h(pathloc, buf, LINKVAL_BUFLEN) ) { - goto cleanup; - } - -#if DEBUG & DEBUG_EVALPATH - fprintf(stderr, "link value is '%s'\n", buf); -#endif - - /* is the link value an absolute path ? */ - if ( DELIM != *buf ) { - /* NO; a relative path */ - - /* we must backup to the link's directory - we - * know only how to do that for NFS, however. - * In this special case, we can avoid recursion. - * Otherwise (i.e. if the link is on another FS), - * we must step into its eval_link_h(). - */ - if (locIsNfs(pathloc)) { - NfsNode node = pathloc->node_access; - int err; - - memcpy( &SERP_FILE(node), - &node->args.dir, - sizeof(node->args.dir) ); - - if (updateAttr(node, 1 /* force */)) - goto cleanup; - - if (SERP_ATTR(node).type != NFDIR) { - errno = ENOTDIR; - goto cleanup; - } - - pathloc->handlers = &nfs_dir_file_handlers; - - err = nfs_evalpath(buf, flags, pathloc); - - /* according to its semantics, - * nfs_evalpath cloned the node attached - * to pathloc. Hence we have to - * release the old one (referring to - * the link; the new clone has been - * updated and refers to the link _value_). - */ - nfsNodeDestroy(node); - - if (err) { - /* nfs_evalpath has set errno; - * pathloc->node_access has no - * valid node attached in this case - */ - rval = RVAL_ERR_BUT_DONT_FREENODE; - goto cleanup; - } - - } else { - if ( ! pathloc->ops->eval_link_h ) { - errno = ENOTSUP; - goto cleanup; - } - if (!pathloc->ops->eval_link_h(pathloc, flags)) { - /* FS is responsible for freeing its pathloc->node_access - * if necessary - */ - rval = RVAL_ERR_BUT_DONT_FREENODE; - goto cleanup; - } - } - } else { - /* link points to an absolute path '/xxx' */ - - /* release this node; filesystem_evaluate_path() will - * lookup a new one. - */ - rtems_filesystem_freenode(pathloc); - - if (rtems_filesystem_evaluate_path(buf, flags, pathloc, 1)) { - goto cleanup; - } - } - - if ( !pathloc->ops->node_type_h ) { - errno = ENOTSUP; - goto cleanup; - } - - type = pathloc->ops->node_type_h(pathloc); - - - /* I dont know what to do about hard links */ - } while ( RTEMS_FILESYSTEM_SYM_LINK == type ); - - rval = RVAL_OK; - -cleanup: - - free(buf); - - if (RVAL_ERR_AND_DO_FREENODE == rval) { - rtems_filesystem_freenode(pathloc); - return -1; - } - - return rval; -} - - -struct _rtems_filesystem_operations_table nfs_fs_ops = { - nfs_evalpath, /* MANDATORY */ - nfs_evalformake, /* MANDATORY; may set errno=ENOSYS and return -1 */ - nfs_link, /* OPTIONAL; may be NULL */ - nfs_unlink, /* OPTIONAL; may be NULL */ - nfs_node_type, /* OPTIONAL; may be NULL; BUG in mount - no test!! */ - nfs_mknod, /* OPTIONAL; may be NULL */ - nfs_chown, /* OPTIONAL; may be NULL */ - nfs_freenode, /* OPTIONAL; may be NULL; (release node_access) */ - nfs_mount, /* OPTIONAL; may be NULL */ - nfs_fsmount_me, /* OPTIONAL; may be NULL -- but this makes NO SENSE */ - nfs_unmount, /* OPTIONAL; may be NULL */ - nfs_fsunmount_me, /* OPTIONAL; may be NULL */ - nfs_utime, /* OPTIONAL; may be NULL */ - nfs_eval_link, /* OPTIONAL; may be NULL */ - nfs_symlink, /* OPTIONAL; may be NULL */ - nfs_readlink, /* OPTIONAL; may be NULL */ -}; - -/***************************************** - File Handlers - - NOTE: the FS generics expect a FS' - evalpath_h() to switch the - pathloc->handlers according - to the pathloc/node's file - type. - We currently have 'file' and - 'directory' handlers and very - few 'symlink' handlers. - - The handlers for each type are - implemented or #defined ZERO - in a 'nfs_file_xxx', - 'nfs_dir_xxx', 'nfs_link_xxx' - sequence below this point. - - In some cases, a common handler, - can be used for all file types. - It is then simply called - 'nfs_xxx'. - *****************************************/ - - -#if 0 -/* from rtems/libio.h for convenience */ -struct rtems_libio_tt { - rtems_driver_name_t *driver; - off_t size; /* size of file */ - off_t offset; /* current offset into file */ - unsigned32 flags; - rtems_filesystem_location_info_t pathinfo; - Objects_Id sem; - unsigned32 data0; /* private to "driver" */ - void *data1; /* ... */ - void *file_info; /* used by file handlers */ - rtems_filesystem_file_handlers_r *handlers; /* type specific handlers */ -}; -#endif - -/* stateless NFS protocol makes this trivial */ -static int nfs_file_open( - rtems_libio_t *iop, - const char *pathname, - unsigned32 flag, - unsigned32 mode -) -{ - iop->file_info = 0; - return 0; -} - -/* reading directories is not stateless; we must - * remember the last 'read' position, i.e. - * the server 'cookie'. We do manage this information - * attached to the iop->file_info. - */ -static int nfs_dir_open( - rtems_libio_t *iop, - const char *pathname, - unsigned32 flag, - unsigned32 mode -) -{ -NfsNode node = iop->pathinfo.node_access; -DirInfo di; - - /* create a readdirargs object and copy the file handle; - * attach to the file_info. - */ - - di = (DirInfo) malloc(sizeof(*di)); - iop->file_info = di; - - if ( !di ) { - errno = ENOMEM; - return -1; - } - - memcpy( &di->readdirargs.dir, - &SERP_FILE(node), - sizeof(di->readdirargs.dir) ); - - /* rewind cookie */ - memset( &di->readdirargs.cookie, - 0, - sizeof(di->readdirargs.cookie) ); - - di->eofreached = FALSE; - - return 0; -} - -#define nfs_link_open 0 - -static int nfs_file_close( - rtems_libio_t *iop -) -{ - return 0; -} - -static int nfs_dir_close( - rtems_libio_t *iop -) -{ - free(iop->file_info); - iop->file_info = 0; - return 0; -} - -#define nfs_link_close 0 - -static int nfs_file_read( - rtems_libio_t *iop, - void *buffer, - unsigned32 count -) -{ -readres rr; -NfsNode node = iop->pathinfo.node_access; -Nfs nfs = node->nfs; - - if (count > NFS_MAXDATA) - count = NFS_MAXDATA; - - SERP_ARGS(node).readarg.offset = iop->offset; - SERP_ARGS(node).readarg.count = count; - SERP_ARGS(node).readarg.totalcount = 0xdeadbeef; - - rr.readres_u.reply.data.data_val = buffer; - - if ( nfscall( nfs->server, - NFSPROC_READ, - xdr_readargs, &SERP_FILE(node), - xdr_readres, &rr) ) { - return -1; - } - - - if (NFS_OK != rr.status) { - rtems_set_errno_and_return_minus_one(rr.status); - } - -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr, - "Read %i (asked for %i) bytes from offset %i to 0x%08x\n", - rr.readres_u.reply.data.data_len, - count, - iop->offset, - rr.readres_u.reply.data.data_val); -#endif - - - return rr.readres_u.reply.data.data_len; -} - -/* this is called by readdir() / getdents() */ -static int nfs_dir_read( - rtems_libio_t *iop, - void *buffer, - unsigned32 count -) -{ -DirInfo di = iop->file_info; -RpcUdpServer server = ((Nfs)iop->pathinfo.mt_entry->fs_info)->server; - - if ( di->eofreached ) - return 0; - - di->ptr = di->buf = buffer; - - /* align + round down the buffer */ - count &= ~ (DIRENT_HEADER_SIZE - 1); - di->len = count; - -#if 0 - /* now estimate the number of entries we should ask for */ - count /= DIRENT_HEADER_SIZE + CONFIG_AVG_NAMLEN; - - /* estimate the encoded size that might take up */ - count *= dirres_entry_size + CONFIG_AVG_NAMLEN; -#else - /* integer arithmetics are better done the other way round */ - count *= dirres_entry_size + CONFIG_AVG_NAMLEN; - count /= DIRENT_HEADER_SIZE + CONFIG_AVG_NAMLEN; -#endif - - if (count > NFS_MAXDATA) - count = NFS_MAXDATA; - - di->readdirargs.count = count; - -#if DEBUG & DEBUG_READDIR - fprintf(stderr, - "Readdir: asking for %i XDR bytes, buffer is %i\n", - count, di->len); -#endif - - if ( nfscall( - server, - NFSPROC_READDIR, - xdr_readdirargs, &di->readdirargs, - xdr_dir_info, di) ) { - return -1; - } - - - if (NFS_OK != di->status) { - rtems_set_errno_and_return_minus_one(di->status); - } - - return (char*)di->ptr - (char*)buffer; -} - -#define nfs_link_read 0 - -static int nfs_file_write( - rtems_libio_t *iop, - const void *buffer, - unsigned32 count -) -{ -NfsNode node = iop->pathinfo.node_access; -Nfs nfs = node->nfs; -int e; - - if (count > NFS_MAXDATA) - count = NFS_MAXDATA; - - SERP_ARGS(node).writearg.beginoffset = 0xdeadbeef; - SERP_ARGS(node).writearg.offset = iop->offset; - SERP_ARGS(node).writearg.totalcount = 0xdeadbeef; - SERP_ARGS(node).writearg.data.data_len = count; - SERP_ARGS(node).writearg.data.data_val = (void*)buffer; - - /* write XDR buffer size will be chosen by nfscall based - * on the PROC specifier - */ - - if ( nfscall( nfs->server, - NFSPROC_WRITE, - xdr_writeargs, &SERP_FILE(node), - xdr_attrstat, &node->serporid) ) { - return -1; - } - - - if (NFS_OK != (e=node->serporid.status) ) { - /* try at least to recover the current attributes */ - updateAttr(node, 1 /* force */); - rtems_set_errno_and_return_minus_one(e); - } - - node->age = nowSeconds(); - - return count; -} - -#define nfs_dir_write 0 -#define nfs_link_write 0 - -/* IOCTL is unneeded/unsupported */ -#ifdef DECLARE_BODY -static int nfs_file_ioctl( - rtems_libio_t *iop, - unsigned32 command, - void *buffer -)DECLARE_BODY -#else -#define nfs_file_ioctl 0 -#define nfs_dir_ioctl 0 -#define nfs_link_ioctl 0 -#endif - -static int nfs_file_lseek( - rtems_libio_t *iop, - off_t length, - int whence -) -{ -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr, - "lseek to %i (length %i, whence %i)\n", - iop->offset, - length, - whence); -#endif - - /* this is particularly easy :-) */ - return iop->offset; -} - -static int nfs_dir_lseek( - rtems_libio_t *iop, - off_t length, - int whence -) -{ -DirInfo di = iop->file_info; - - /* we don't support anything other than - * rewinding - */ - if (SEEK_SET != whence || 0 != length) { - errno = ENOTSUP; - return -1; - } - - /* rewind cookie */ - memset( &di->readdirargs.cookie, - 0, - sizeof(di->readdirargs.cookie) ); - - di->eofreached = FALSE; - - return iop->offset; -} - -#define nfs_link_lseek 0 - -#if 0 /* structure types for reference */ -struct fattr { - ftype type; - u_int mode; - u_int nlink; - u_int uid; - u_int gid; - u_int size; - u_int blocksize; - u_int rdev; - u_int blocks; - u_int fsid; - u_int fileid; - nfstime atime; - nfstime mtime; - nfstime ctime; -}; - -struct stat -{ - dev_t st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - dev_t st_rdev; - off_t st_size; - /* SysV/sco doesn't have the rest... But Solaris, eabi does. */ -#if defined(__svr4__) && !defined(__PPC__) && !defined(__sun__) - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -#else - time_t st_atime; - long st_spare1; - time_t st_mtime; - long st_spare2; - time_t st_ctime; - long st_spare3; - long st_blksize; - long st_blocks; - long st_spare4[2]; -#endif -}; -#endif - -/* common for file/dir/link */ -static int nfs_fstat( - rtems_filesystem_location_info_t *loc, - struct stat *buf -) -{ -NfsNode node = loc->node_access; -fattr *fa = &SERP_ATTR(node); - - if (updateAttr(node, 0 /* only if old */)) { - return -1; - } - -/* done by caller - memset(buf, 0, sizeof(*buf)); - */ - - /* translate */ - - /* one of the branches hopefully is optimized away */ - if (sizeof(ino_t) < sizeof(u_int)) { - buf->st_dev = NFS_MAKE_DEV_T_INO_HACK((NfsNode)loc->node_access); - } else { - buf->st_dev = NFS_MAKE_DEV_T((NfsNode)loc->node_access); - } - buf->st_mode = fa->mode; - buf->st_nlink = fa->nlink; - buf->st_uid = fa->uid; - buf->st_gid = fa->gid; - buf->st_size = fa->size; - /* TODO: set to "preferred size" of this NFS client implementation */ - buf->st_blksize = fa->blocksize; - buf->st_rdev = fa->rdev; - buf->st_blocks = fa->blocks; - buf->st_ino = fa->fileid; - buf->st_atime = fa->atime.seconds; - buf->st_mtime = fa->mtime.seconds; - buf->st_ctime = fa->ctime.seconds; - -#if 0 /* NFS should return the modes */ - switch(fa->type) { - default: - case NFNON: - case NFBAD: - break; - - case NFSOCK: buf->st_mode |= S_IFSOCK; break; - case NFFIFO: buf->st_mode |= S_IFIFO; break; - case NFREG : buf->st_mode |= S_IFREG; break; - case NFDIR : buf->st_mode |= S_IFDIR; break; - case NFBLK : buf->st_mode |= S_IFBLK; break; - case NFCHR : buf->st_mode |= S_IFCHR; break; - case NFLNK : buf->st_mode |= S_IFLNK; break; - } -#endif - - return 0; -} - -/* a helper which does the real work for - * a couple of handlers (such as chmod, - * ftruncate or utime) - */ -static int -nfs_sattr(NfsNode node, sattr *arg, u_long mask) -{ - -rtems_clock_time_value now; -nfstime nfsnow, t; -int e; -u_int mode; - - if (updateAttr(node, 0 /* only if old */)) - return -1; - - rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); - - /* TODO: add rtems EPOCH - UNIX EPOCH seconds */ - nfsnow.seconds = now.seconds; - nfsnow.useconds = now.microseconds; - - /* merge permission bits into existing type bits */ - mode = SERP_ATTR(node).mode; - if (mask & SATTR_MODE) { - mode &= S_IFMT; - mode |= arg->mode & ~S_IFMT; - } - SERP_ARGS(node).sattrarg.attributes.mode = mode; - - SERP_ARGS(node).sattrarg.attributes.uid = - (mask & SATTR_UID) ? arg->uid : SERP_ATTR(node).uid; - - SERP_ARGS(node).sattrarg.attributes.gid = - (mask & SATTR_GID) ? arg->gid : SERP_ATTR(node).gid; - - SERP_ARGS(node).sattrarg.attributes.size = - (mask & SATTR_SIZE) ? arg->size : SERP_ATTR(node).size; - - if (mask & SATTR_ATIME) - t = arg->atime; - else if (mask & SATTR_TOUCHA) - t = nfsnow; - else - t = SERP_ATTR(node).atime; - SERP_ARGS(node).sattrarg.attributes.atime = t; - - if (mask & SATTR_ATIME) - t = arg->mtime; - else if (mask & SATTR_TOUCHA) - t = nfsnow; - else - t = SERP_ATTR(node).mtime; - SERP_ARGS(node).sattrarg.attributes.mtime = t; - - node->serporid.status = NFS_OK; - - if ( nfscall( node->nfs->server, - NFSPROC_SETATTR, - xdr_sattrargs, &SERP_FILE(node), - xdr_attrstat, &node->serporid) ) { -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr, - "nfs_sattr (mask 0x%08x): %s", - mask, - strerror(errno)); -#endif - return -1; - } - - if (NFS_OK != (e=node->serporid.status) ) { -#if DEBUG & DEBUG_SYSCALLS - fprintf(stderr,"nfs_sattr: %s\n",strerror(e)); -#endif - /* try at least to recover the current attributes */ - updateAttr(node, 1 /* force */); - rtems_set_errno_and_return_minus_one(e); - } - - node->age = nowSeconds(); - - return 0; -} - - -/* common for file/dir/link */ -static int nfs_fchmod( - rtems_filesystem_location_info_t *loc, - mode_t mode -) -{ -sattr arg; - - arg.mode = mode; - return nfs_sattr(loc->node_access, &arg, SATTR_MODE); - -} - -/* just set the size attribute to 'length' - * the server will take care of the rest :-) - */ -static int nfs_file_ftruncate( - rtems_libio_t *iop, - off_t length -) -{ -sattr arg; - - arg.size = length; - return nfs_sattr(iop->pathinfo.node_access, - &arg, - SATTR_SIZE | SATTR_TOUCH); -} - -#define nfs_dir_ftruncate 0 -#define nfs_link_ftruncate 0 - -/* not implemented */ -#ifdef DECLARE_BODY -static int nfs_file_fpathconf( - rtems_libio_t *iop, - int name -)DECLARE_BODY -#else -#define nfs_file_fpathconf 0 -#define nfs_dir_fpathconf 0 -#define nfs_link_fpathconf 0 -#endif - -/* unused */ -#ifdef DECLARE_BODY -static int nfs_file_fsync( - rtems_libio_t *iop -)DECLARE_BODY -#else -#define nfs_file_fsync 0 -#define nfs_dir_fsync 0 -#define nfs_link_fsync 0 -#endif - -/* unused */ -#ifdef DECLARE_BODY -static int nfs_file_fdatasync( - rtems_libio_t *iop -)DECLARE_BODY -#else -#define nfs_file_fdatasync 0 -#define nfs_dir_fdatasync 0 -#define nfs_link_fdatasync 0 -#endif - -/* unused */ -#ifdef DECLARE_BODY -static int nfs_file_fcntl( - int cmd, - rtems_libio_t *iop -)DECLARE_BODY -#else -#define nfs_file_fcntl 0 -#define nfs_dir_fcntl 0 -#define nfs_link_fcntl 0 -#endif - -/* files and symlinks are removed - * by the common nfs_unlink() routine. - * NFS has a different NFSPROC_RMDIR - * call, though... - */ -static int nfs_dir_rmnod( - rtems_filesystem_location_info_t *pathloc /* IN */ -) -{ - return nfs_do_unlink(pathloc, NFSPROC_RMDIR); -} - -/* the file handlers table */ -static -struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers = { - nfs_file_open, /* OPTIONAL; may be NULL */ - nfs_file_close, /* OPTIONAL; may be NULL */ - nfs_file_read, /* OPTIONAL; may be NULL */ - nfs_file_write, /* OPTIONAL; may be NULL */ - nfs_file_ioctl, /* OPTIONAL; may be NULL */ - nfs_file_lseek, /* OPTIONAL; may be NULL */ - nfs_fstat, /* OPTIONAL; may be NULL */ - nfs_fchmod, /* OPTIONAL; may be NULL */ - nfs_file_ftruncate, /* OPTIONAL; may be NULL */ - nfs_file_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ - nfs_file_fsync, /* OPTIONAL; may be NULL */ - nfs_file_fdatasync, /* OPTIONAL; may be NULL */ - nfs_file_fcntl, /* OPTIONAL; may be NULL */ - nfs_unlink, /* OPTIONAL; may be NULL */ -}; - -/* the directory handlers table */ -static -struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers = { - nfs_dir_open, /* OPTIONAL; may be NULL */ - nfs_dir_close, /* OPTIONAL; may be NULL */ - nfs_dir_read, /* OPTIONAL; may be NULL */ - nfs_dir_write, /* OPTIONAL; may be NULL */ - nfs_dir_ioctl, /* OPTIONAL; may be NULL */ - nfs_dir_lseek, /* OPTIONAL; may be NULL */ - nfs_fstat, /* OPTIONAL; may be NULL */ - nfs_fchmod, /* OPTIONAL; may be NULL */ - nfs_dir_ftruncate, /* OPTIONAL; may be NULL */ - nfs_dir_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ - nfs_dir_fsync, /* OPTIONAL; may be NULL */ - nfs_dir_fdatasync, /* OPTIONAL; may be NULL */ - nfs_dir_fcntl, /* OPTIONAL; may be NULL */ - nfs_dir_rmnod, /* OPTIONAL; may be NULL */ -}; - -/* the link handlers table */ -static -struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers = { - nfs_link_open, /* OPTIONAL; may be NULL */ - nfs_link_close, /* OPTIONAL; may be NULL */ - nfs_link_read, /* OPTIONAL; may be NULL */ - nfs_link_write, /* OPTIONAL; may be NULL */ - nfs_link_ioctl, /* OPTIONAL; may be NULL */ - nfs_link_lseek, /* OPTIONAL; may be NULL */ - nfs_fstat, /* OPTIONAL; may be NULL */ - nfs_fchmod, /* OPTIONAL; may be NULL */ - nfs_link_ftruncate, /* OPTIONAL; may be NULL */ - nfs_link_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ - nfs_link_fsync, /* OPTIONAL; may be NULL */ - nfs_link_fdatasync, /* OPTIONAL; may be NULL */ - nfs_link_fcntl, /* OPTIONAL; may be NULL */ - nfs_unlink, /* OPTIONAL; may be NULL */ -}; - -/* we need a dummy driver entry table to get a - * major number from the system - */ -static -rtems_device_driver nfs_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) -{ - /* we don't really use this routine because - * we cannot supply an argument (contrary - * to what the 'arg' parameter suggests - it - * is always set to 0 by the generics :-() - * and because we don't want the user to - * have to deal with the major number (which - * OTOH is something WE are interested in. The - * only reason for using this API was getting - * a major number, after all). - * - * Something must be present, however, to - * reserve a slot in the driver table. - */ - return RTEMS_SUCCESSFUL; -} - -static rtems_driver_address_table drvNfs = { - nfs_initialize, - 0, /* open */ - 0, /* close */ - 0, /* read */ - 0, /* write */ - 0 /* control */ -}; - -/* Dump a list of the currently mounted NFS to a file */ -int -nfsMountsShow(FILE *f) -{ -char *mntpt = 0; -Nfs nfs; - - if (!f) - f = stdout; - - if ( !(mntpt=malloc(MAXPATHLEN)) ) { - fprintf(stderr,"nfsMountsShow(): no memory\n"); - return -1; - } - - fprintf(f,"Currently Mounted NFS:\n"); - - LOCK(nfsGlob.llock); - - for (nfs = nfsGlob.mounted_fs; nfs; nfs=nfs->next) { - fprintf(f,"%s on ", nfs->mt_entry->dev); - if (rtems_filesystem_resolve_location(mntpt, MAXPATHLEN, &nfs->mt_entry->mt_fs_root)) - fprintf(f,"\n"); - else - fprintf(f,"%s\n",mntpt); - } - - UNLOCK(nfsGlob.llock); - - free(mntpt); - return 0; -} - -/* convenience wrapper - * - * NOTE: this routine calls NON-REENTRANT - * gethostbyname() if the host is - * not in 'dot' notation. - */ -int -nfsMount(char *uidhost, char *path, char *mntpoint) -{ -rtems_filesystem_mount_table_entry_t *mtab; -struct stat st; -int devl; -char *host; -int rval = -1; -char *dev = 0; - - if (!uidhost || !path || !mntpoint) { - fprintf(stderr,"usage: nfsMount(""[uid.gid@]host"",""path"",""mountpoint"")\n"); - nfsMountsShow(stderr); - return -1; - } - - if ( !(dev = malloc((devl=strlen(uidhost) + 20 + strlen(path)+1))) ) { - fprintf(stderr,"nfsMount: out of memory\n"); - return -1; - } - - /* Try to create the mount point if nonexistent */ - if (stat(mntpoint, &st)) { - if (ENOENT != errno) { - perror("nfsMount trying to create mount point - stat failed"); - goto cleanup; - } else if (mkdir(mntpoint,0777)) { - perror("nfsMount trying to create mount point"); - goto cleanup; - } - } - - if ( !(host=strchr(uidhost,UIDSEP)) ) { - host = uidhost; - } else { - host++; - } - - if (isdigit(*host)) { - /* avoid using gethostbyname */ - sprintf(dev,"%s:%s",uidhost,path); - } else { - struct hostent *h; - - /* copy the uid part (hostname will be - * overwritten) - */ - strcpy(dev, uidhost); - - /* NOTE NOTE NOTE: gethostbyname is NOT - * thread safe. This is UGLY - */ - -/* BEGIN OF NON-THREAD SAFE REGION */ - - h = gethostbyname(host); - - if ( !h || - !inet_ntop( AF_INET, - (struct in_addr*)h->h_addr_list[0], - dev + (host - uidhost), - devl - (host - uidhost) ) - ) { - fprintf(stderr,"nfsMount: host '%s' not found\n",host); - goto cleanup; - } - -/* END OF NON-THREAD SAFE REGION */ - - /* append ':' */ - strcat(dev,":"); - strcat(dev,path); - } - - printf("Trying to mount %s on %s\n",dev,mntpoint); - - if (mount(&mtab, - &nfs_fs_ops, - RTEMS_FILESYSTEM_READ_WRITE, - dev, - mntpoint)) { - perror("nfsMount - mount"); - goto cleanup; - } - - rval = 0; - -cleanup: - free(dev); - return rval; -} - -/* HERE COMES A REALLY UGLY HACK */ - -/* This is stupid; it is _very_ hard to find the path - * leading to a rtems_filesystem_location_info_t node :-( - * The only easy way is making the location the current - * directory and issue a getcwd(). - * However, since we don't want to tamper with the - * current directory, we must create a separate - * task to do the job for us - sigh. - */ - -typedef struct ResolvePathArgRec_ { - rtems_filesystem_location_info_t *loc; /* IN: location to resolve */ - char *buf; /* IN/OUT: buffer where to put the path */ - int len; /* IN: buffer length */ - rtems_id sync; /* IN: synchronization */ - rtems_status_code status; /* OUT: result */ -} ResolvePathArgRec, *ResolvePathArg; - -static void -resolve_path(rtems_task_argument arg) -{ -ResolvePathArg rpa = (ResolvePathArg)arg; -rtems_filesystem_location_info_t old; - - /* IMPORTANT: let the helper task have its own libio environment (i.e. cwd) */ - if (RTEMS_SUCCESSFUL == (rpa->status = rtems_libio_set_private_env())) { - - old = rtems_filesystem_current; - - rtems_filesystem_current = *(rpa->loc); - - if ( !getcwd(rpa->buf, rpa->len) ) - rpa->status = RTEMS_UNSATISFIED; - - /* must restore the cwd because 'freenode' will be called on it */ - rtems_filesystem_current = old; - } - rtems_semaphore_release(rpa->sync); - rtems_task_delete(RTEMS_SELF); -} - - -/* a utility routine to find the path leading to a - * rtems_filesystem_location_info_t node - * - * INPUT: 'loc' and a buffer 'buf' (length 'len') to hold the - * path. - * OUTPUT: path copied into 'buf' - * - * RETURNS: 0 on success, RTEMS error code on error. - */ -rtems_status_code -rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc) -{ -ResolvePathArgRec arg; -rtems_id tid = 0; -rtems_task_priority pri; -rtems_status_code status; - - arg.loc = loc; - arg.buf = buf; - arg.len = len; - arg.sync = 0; - - status = rtems_semaphore_create( - rtems_build_name('r','e','s','s'), - 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE, - 0, - &arg.sync); - - if (RTEMS_SUCCESSFUL != status) - goto cleanup; - - rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &pri); - - status = rtems_task_create( - rtems_build_name('r','e','s','s'), - pri, - RTEMS_MINIMUM_STACK_SIZE + 50000, - RTEMS_DEFAULT_MODES, - RTEMS_DEFAULT_ATTRIBUTES, - &tid); - - if (RTEMS_SUCCESSFUL != status) - goto cleanup; - - status = rtems_task_start(tid, resolve_path, (rtems_task_argument)&arg); - - if (RTEMS_SUCCESSFUL != status) { - rtems_task_delete(tid); - goto cleanup; - } - - - /* synchronize with the helper task */ - rtems_semaphore_obtain(arg.sync, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - - status = arg.status; - -cleanup: - if (arg.sync) - rtems_semaphore_delete(arg.sync); - - return status; -} diff --git a/rtemsNfs-1.1/src/nfs.modini.c b/rtemsNfs-1.1/src/nfs.modini.c deleted file mode 100644 index 834102e..0000000 --- a/rtemsNfs-1.1/src/nfs.modini.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "librtemsNfs.h" - -/* CEXP dynamic loader support */ - -void -_cexpModuleInitialize(void *mod) -{ -#if defined(DEBUG) - /* print load address (in case we crash while initializing) */ -unsigned lr; - __asm__ __volatile__( - " bl thisis_loaded_at \n" - "thisis_loaded_at: \n" - " mflr %0 \n" - : "=r"(lr) ::"lr"); - printf("thisis_loaded_at: 0x%08x\n",lr); -#endif - nfsInit(0,0); -} - -int -_cexpModuleFinalize(void *mod) -{ - return nfsCleanup(); -} - - diff --git a/rtemsNfs-1.1/src/rpcio.c b/rtemsNfs-1.1/src/rpcio.c deleted file mode 100644 index 667ba6a..0000000 --- a/rtemsNfs-1.1/src/rpcio.c +++ /dev/null @@ -1,1717 +0,0 @@ -/* $Id$ */ - -/* RPC multiplexor for a multitasking environment */ - -/* Author: Till Straumann , 2002 */ - -/* This code funnels arbitrary task's UDP/RPC requests - * through one socket to arbitrary servers. - * The replies are gathered and dispatched to the - * requestors. - * One task handles all the sending and receiving - * work including retries. - * It is up to the requestor, however, to do - * the XDR encoding of the arguments / decoding - * of the results (except for the RPC header which - * is handled by the daemon). - * - * Copyright 2002, Stanford University and - * Till Straumann - * - * Stanford Notice - * *************** - * - * Acknowledgement of sponsorship - * * * * * * * * * * * * * * * * * - * This software was produced by the Stanford Linear Accelerator Center, - * Stanford University, under Contract DE-AC03-76SFO0515 with the Department - * of Energy. - * - * Government disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, - * or assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately - * owned rights. - * - * Stanford disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * This product is subject to the EPICS open license - * - - - - - - - - - - - - - - - - - - - - - - - - - - * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php - * for more information. - * - * Maintenance of notice - * - - - - - - - - - - - - * In the interest of clarity regarding the origin and status of this - * software, Stanford University requests that any recipient of it maintain - * this notice affixed to any distribution by the recipient that contains a - * copy or derivative of this software. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rpcio.h" - -/****************************************************************/ -/* CONFIGURABLE PARAMETERS */ -/****************************************************************/ - -#define MBUF_RX /* If defined: use mbuf XDR stream for - * decoding directly out of mbufs - * Otherwise, the regular 'recvfrom()' - * interface will be used involving an - * extra buffer allocation + copy step. - */ - -#define MBUF_TX /* If defined: avoid copying data when - * sending. Instead, use a wrapper to - * 'sosend()' which will point an MBUF - * directly to our buffer space. - * Note that the BSD stack does not copy - * data when fragmenting packets - it - * merely uses an mbuf chain pointing - * into different areas of the data. - * - * If undefined, the regular 'sendto()' - * interface is used. - */ - -/* daemon task parameters */ -#define RPCIOD_STACK 10000 -#define RPCIOD_PRIO 50 - -/* depth of the message queue for sending - * RPC requests to the daemon - */ -#define RPCIOD_QDEPTH 20 - -/* Maximum retry limit for retransmission */ -#define RPCIOD_RETX_CAP_S 3 /* seconds */ - -/* Default timeout for RPC calls */ -#define RPCIOD_DEFAULT_TIMEOUT (&_rpc_default_timeout) -static struct timeval _rpc_default_timeout = { 10 /* secs */, 0 /* usecs */ }; - -/* how many times should we try to resend a failed - * transaction with refreshed AUTHs - */ -#define RPCIOD_REFRESH 2 - -/* Events we are using; the RPC_EVENT - * MUST NOT be used by any application - * thread doing RPC IO (e.g. NFS) - */ -#define RTEMS_RPC_EVENT RTEMS_EVENT_30 /* THE event used by RPCIO. Every task doing - * RPC IO will receive this - hence it is - * RESERVED - */ -#define RPCIOD_RX_EVENT RTEMS_EVENT_1 /* Events the RPCIOD is using/waiting for */ -#define RPCIOD_TX_EVENT RTEMS_EVENT_2 -#define RPCIOD_KILL_EVENT RTEMS_EVENT_3 /* send to the daemon to kill it */ - -#define LD_XACT_HASH 8 /* ld of the size of the transaction hash table */ - - -/* Debugging Flags */ - -/* NOTE: defining DEBUG 0 leaves some 'assert()' paranoia checks - * but produces no output - */ - -#define DEBUG_TRACE_XACT (1<<0) -#define DEBUG_EVENTS (1<<1) -#define DEBUG_MALLOC (1<<2) -#define DEBUG_TIMEOUT (1<<3) -#define DEBUG_PACKLOSS (1<<4) /* This introduces random, artificial packet losses to test retransmission */ - -#define DEBUG_PACKLOSS_FRACT (0xffffffff/10) - -/* USE PARENTHESIS WHEN 'or'ing MULTIPLE FLAGS: (DEBUG_XX | DEBUG_YY) */ -#define DEBUG (0) - -/****************************************************************/ -/* END OF CONFIGURABLE SECTION */ -/****************************************************************/ - -/* prevent rollover of our timers by readjusting the epoch on the fly */ -#if (DEBUG) & DEBUG_TIMEOUT -#define RPCIOD_EPOCH_SECS 10 -#else -#define RPCIOD_EPOCH_SECS 10000 -#endif - -#ifdef DEBUG -#define ASSERT(arg) assert(arg) -#else -#define ASSERT(arg) if (arg) -#endif - -/****************************************************************/ -/* MACROS */ -/****************************************************************/ - - -#define XACT_HASHS (1<<(LD_XACT_HASH)) /* the hash table size derived from the ld */ -#define XACT_HASH_MSK ((XACT_HASHS)-1) /* mask to extract the hash index from a RPC-XID */ - - -#define MU_LOCK(mutex) do { \ - assert( \ - RTEMS_SUCCESSFUL == \ - rtems_semaphore_obtain( \ - (mutex), \ - RTEMS_WAIT, \ - RTEMS_NO_TIMEOUT \ - ) ); \ - } while(0) - -#define MU_UNLOCK(mutex) do { \ - assert( \ - RTEMS_SUCCESSFUL == \ - rtems_semaphore_release( \ - (mutex) \ - ) ); \ - } while(0) - -#define MU_CREAT(pmutex) do { \ - assert( \ - RTEMS_SUCCESSFUL == \ - rtems_semaphore_create( \ - rtems_build_name( \ - 'R','P','C','l' \ - ), \ - 1, \ - MUTEX_ATTRIBUTES, \ - 0, \ - (pmutex)) ); \ - } while (0) - - -#define MU_DESTROY(mutex) do { \ - assert( \ - RTEMS_SUCCESSFUL == \ - rtems_semaphore_delete( \ - mutex \ - ) ); \ - } while (0) - -#define MUTEX_ATTRIBUTES (RTEMS_LOCAL | \ - RTEMS_PRIORITY | \ - RTEMS_INHERIT_PRIORITY | \ - RTEMS_BINARY_SEMAPHORE) - -#define FIRST_ATTEMPT 0x88888888 /* some time that is never reached */ - -/****************************************************************/ -/* TYPE DEFINITIONS */ -/****************************************************************/ - -typedef rtems_interval TimeoutT; - -/* 100000th implementation of a doubly linked list; - * since only one thread is looking at these, - * we need no locking - */ -typedef struct ListNodeRec_ { - struct ListNodeRec_ *next, *prev; -} ListNodeRec, *ListNode; - - -/* Structure representing an RPC server */ -typedef struct RpcUdpServerRec_ { - RpcUdpServer next; /* linked list of all servers; protected by hlock */ - struct sockaddr_in addr; - AUTH *auth; - rtems_id authlock; /* must MUTEX the auth object - it's not clear - * what is better: - * 1 having one (MUTEXed) auth per server - * who is shared among all transactions - * using that server - * 2 maintaining an AUTH per transaction - * (there are then other options: manage - * XACT pools on a per-server basis instead - * of associating a server with a XACT when - * sending) - * experience will show if the current (1) - * approach has to be changed. - */ - TimeoutT retry_period; /* dynamically adjusted retry period - * (based on packet roundtrip time) - */ - /* STATISTICS */ - unsigned long retrans; /* how many retries were issued by this server */ - unsigned long requests; /* how many requests have been sent */ - unsigned long timeouts; /* how many requests have timed out */ - unsigned long errors; /* how many errors have occurred (other than timeouts) */ - char name[20]; /* server's address in IP 'dot' notation */ -} RpcUdpServerRec; - -typedef union RpcBufU_ { - u_long xid; - char buf[1]; -} RpcBufU, *RpcBuf; - -/* RX Buffer implementation; this is either - * an MBUF chain (MBUF_RX configuration) - * or a buffer allocated from the heap - * where recvfrom copies the (encoded) reply - * to. The XDR routines the copy/decode - * it into the user's data structures. - */ -#ifdef MBUF_RX -typedef struct mbuf * RxBuf; /* an MBUF chain */ -static void bufFree(struct mbuf **m); -#define XID(ibuf) (*(mtod((ibuf), u_long *))) -extern void xdrmbuf_create(XDR *, struct mbuf *, enum xdr_op); -#else -typedef RpcBuf RxBuf; -#define bufFree(b) do { MY_FREE(*(b)); *(b)=0; } while(0) -#define XID(ibuf) ((ibuf)->xid) -#endif - -/* A RPC 'transaction' consisting - * of server and requestor information, - * buffer space and an XDR object - * (for encoding arguments). - */ -typedef struct RpcUdpXactRec_ { - ListNodeRec node; /* so we can put XACTs on a list */ - RpcUdpServer server; /* server this XACT goes to */ - long lifetime; /* during the lifetime, retry attempts are made */ - long tolive; /* lifetime timer */ - struct rpc_err status; /* RPC reply error status */ - long age; /* age info; needed to manage retransmission */ - long trip; /* record round trip time in ticks */ - rtems_id requestor; /* the task waiting for this XACT to complete */ - RpcUdpXactPool pool; /* if this XACT belong to a pool, this is it */ - XDR xdrs; /* argument encoder stream */ - int xdrpos; /* stream position after the (permanent) header */ - xdrproc_t xres; /* reply decoder proc - TODO needn't be here */ - caddr_t pres; /* reply decoded obj - TODO needn't be here */ -#ifndef MBUF_RX - int ibufsize; /* size of the ibuf (bytes) */ -#endif -#ifdef MBUF_TX - int refcnt; /* mbuf external storage reference count */ -#endif - int obufsize; /* size of the obuf (bytes) */ - RxBuf ibuf; /* pointer to input buffer assigned by daemon */ - RpcBufU obuf; /* output buffer (encoded args) APPENDED HERE */ -} RpcUdpXactRec; - -typedef struct RpcUdpXactPoolRec_ { - rtems_id box; - int prog; - int version; - int xactSize; -} RpcUdpXactPoolRec; - -/* a global hash table where all 'living' transaction - * objects are registered. - * A number of bits in a transaction's XID maps 1:1 to - * an index in this table. Hence, the XACT matching - * an RPC/UDP reply packet can quickly be found - * The size of this table imposes a hard limit on the - * number of all created transactions in the system. - */ -static RpcUdpXact xactHashTbl[XACT_HASHS]={0}; - -/* forward declarations */ -static RpcUdpXact -sockRcv(void); - -static void -rpcio_daemon(rtems_task_argument); - -#ifdef MBUF_TX -ssize_t -sendto_nocpy ( - int s, - const void *buf, size_t buflen, - int flags, - const struct sockaddr *toaddr, int tolen, - void *closure, - void (*freeproc)(caddr_t, u_int), - void (*refproc)(caddr_t, u_int) -); -static void paranoia_free(caddr_t closure, u_int size); -static void paranoia_ref (caddr_t closure, u_int size); -#define SENDTO sendto_nocpy -#else -#define SENDTO sendto -#endif - -static RpcUdpServer rpcUdpServers = 0; /* linked list of all servers; protected by llock */ - -static int ourSock = -1; /* the socket we are using for communication */ -static rtems_id rpciod = 0; /* task id of the RPC daemon */ -static rtems_id msgQ = 0; /* message queue where the daemon picks up - * requests - */ -static rtems_id llock = 0; /* MUTEX protecting the server list */ -static rtems_id hlock = 0; /* MUTEX protecting the hash table and the list of servers */ -static rtems_id fini = 0; /* a synchronization semaphore we use during - * module cleanup / driver unloading - */ -static rtems_interval ticksPerSec; /* cached system clock rate (WHO IS ASSUMED NOT - * TO CHANGE) - */ -#if (DEBUG) & DEBUG_MALLOC -/* malloc wrappers for debugging */ -static int nibufs = 0; - -static inline void *MY_MALLOC(int s) -{ - if (s) { - void *rval; - MU_LOCK(hlock); - assert(nibufs++ < 2000); - MU_UNLOCK(hlock); - assert(rval = malloc(s)); - return rval; - } - return 0; -} - -static inline void *MY_CALLOC(int n, int s) -{ - if (s) { - void *rval; - MU_LOCK(hlock); - assert(nibufs++ < 2000); - MU_UNLOCK(hlock); - assert(rval = calloc(n,s)); - return rval; - } - return 0; -} - - -static inline void MY_FREE(void *p) -{ - if (p) { - MU_LOCK(hlock); - nibufs--; - MU_UNLOCK(hlock); - free(p); - } -} -#else -#define MY_MALLOC malloc -#define MY_CALLOC calloc -#define MY_FREE free -#endif - -static inline bool_t -locked_marshal(RpcUdpServer s, XDR *xdrs) -{ -bool_t rval; - MU_LOCK(s->authlock); - rval = AUTH_MARSHALL(s->auth, xdrs); - MU_UNLOCK(s->authlock); - return rval; -} - -/* Locked operations on a server's auth object */ -static inline bool_t -locked_validate(RpcUdpServer s, struct opaque_auth *v) -{ -bool_t rval; - MU_LOCK(s->authlock); - rval = AUTH_VALIDATE(s->auth, v); - MU_UNLOCK(s->authlock); - return rval; -} - -static inline bool_t -locked_refresh(RpcUdpServer s) -{ -bool_t rval; - MU_LOCK(s->authlock); - rval = AUTH_REFRESH(s->auth); - MU_UNLOCK(s->authlock); - return rval; -} - -/* Create a server object - * - */ -enum clnt_stat -rpcUdpServerCreate( - struct sockaddr_in *paddr, - int prog, - int vers, - u_long uid, - u_long gid, - RpcUdpServer *psrv - ) -{ -RpcUdpServer rval; -u_short port; -char hname[MAX_MACHINE_NAME + 1]; -int theuid, thegid; -int thegids[NGRPS]; -gid_t gids[NGROUPS]; -int len,i; -AUTH *auth; -enum clnt_stat pmap_err; -struct pmap pmaparg; - - if ( gethostname(hname, MAX_MACHINE_NAME) ) { - fprintf(stderr, - "RPCIO - error: I have no hostname ?? (%s)\n", - strerror(errno)); - return RPC_UNKNOWNHOST; - } - - if ( (len = getgroups(NGROUPS, gids) < 0 ) ) { - fprintf(stderr, - "RPCIO - error: I unable to get group ids (%s)\n", - strerror(errno)); - return RPC_FAILED; - } - - if ( len > NGRPS ) - len = NGRPS; - - for (i=0; isin_port) { - - paddr->sin_port = htons(PMAPPORT); - - pmaparg.pm_prog = prog; - pmaparg.pm_vers = vers; - pmaparg.pm_prot = IPPROTO_UDP; - pmaparg.pm_port = 0; /* not needed or used */ - - - /* dont use non-reentrant pmap_getport ! */ - - pmap_err = rpcUdpCallRp( - paddr, - PMAPPROG, - PMAPVERS, - PMAPPROC_GETPORT, - xdr_pmap, - &pmaparg, - xdr_u_short, - &port, - uid, - gid, - 0); - - if ( RPC_SUCCESS != pmap_err ) { - paddr->sin_port = 0; - return pmap_err; - } - - paddr->sin_port = htons(port); - } - - if (0==paddr->sin_port) { - return RPC_PROGNOTREGISTERED; - } - - rval = (RpcUdpServer)MY_MALLOC(sizeof(*rval)); - memset(rval, 0, sizeof(*rval)); - - if (!inet_ntop(AF_INET, &paddr->sin_addr, rval->name, sizeof(rval->name))) - sprintf(rval->name,"?.?.?.?"); - rval->addr = *paddr; - - /* start with a long retransmission interval - it - * will be adapted dynamically - */ - rval->retry_period = RPCIOD_RETX_CAP_S * ticksPerSec; - - rval->auth = auth; - - MU_CREAT( &rval->authlock ); - - /* link into list */ - MU_LOCK( llock ); - rval->next = rpcUdpServers; - rpcUdpServers = rval; - MU_UNLOCK( llock ); - - *psrv = rval; - return RPC_SUCCESS; -} - -void -rpcUdpServerDestroy(RpcUdpServer s) -{ -RpcUdpServer prev; - if (!s) - return; - /* we should probably verify (but how?) that nobody - * (at least: no outstanding XACTs) is using this - * server; - */ - - /* remove from server list */ - MU_LOCK(llock); - prev = rpcUdpServers; - if ( s == prev ) { - rpcUdpServers = s->next; - } else { - for ( ; prev ; prev = prev->next) { - if (prev->next == s) { - prev->next = s->next; - break; - } - } - } - MU_UNLOCK(llock); - - /* MUST have found it */ - assert(prev); - - auth_destroy(s->auth); - - MU_DESTROY(s->authlock); - MY_FREE(s); -} - -int -rpcUdpStats(FILE *f) -{ -RpcUdpServer s; - - if (!f) f = stdout; - - fprintf(f,"RPCIOD statistics:\n"); - - MU_LOCK(llock); - for (s = rpcUdpServers; s; s=s->next) { - fprintf(f,"\nServer -- %s:\n", s->name); - fprintf(f," requests sent: %10ld, retransmitted: %10ld\n", - s->requests, s->retrans); - fprintf(f," timed out: %10ld, send errors: %10ld\n", - s->timeouts, s->errors); - fprintf(f," current retransmission interval: %dms\n", - s->retry_period * 1000 / ticksPerSec ); - } - MU_UNLOCK(llock); - - return 0; -} - -RpcUdpXact -rpcUdpXactCreate( - u_long program, - u_long version, - u_long size - ) -{ -RpcUdpXact rval=0; -struct rpc_msg header; -register int i,j; - - if (!size) - size = UDPMSGSIZE; - /* word align */ - size = (size + 3) & ~3; - - rval = (RpcUdpXact)MY_CALLOC(1,sizeof(*rval) - sizeof(rval->obuf) + size); - - if (rval) { - - header.rm_xid = 0; - header.rm_direction = CALL; - header.rm_call.cb_rpcvers = RPC_MSG_VERSION; - header.rm_call.cb_prog = program; - header.rm_call.cb_vers = version; - xdrmem_create(&(rval->xdrs), rval->obuf.buf, size, XDR_ENCODE); - - if (!xdr_callhdr(&(rval->xdrs), &header)) { - MY_FREE(rval); - return 0; - } - /* pick a free table slot and initialize the XID */ - rval->obuf.xid = time(0) ^ (unsigned long)rval; - MU_LOCK(hlock); - i=j=(rval->obuf.xid & XACT_HASH_MSK); - if (msgQ) { - /* if there's no message queue, refuse to - * give them transactions; we might be in the process to - * go away... - */ - do { - i=(i+1) & XACT_HASH_MSK; /* cheap modulo */ - if (!xactHashTbl[i]) { -#if (DEBUG) & DEBUG_TRACE_XACT - fprintf(stderr,"RPCIO: entering index %i, val %x\n",i,rval); -#endif - xactHashTbl[i]=rval; - j=-1; - break; - } - } while (i!=j); - } - MU_UNLOCK(hlock); - if (i==j) { - XDR_DESTROY(&rval->xdrs); - MY_FREE(rval); - return 0; - } - rval->obuf.xid = (rval->obuf.xid << LD_XACT_HASH) | i; - rval->xdrpos = XDR_GETPOS(&(rval->xdrs)); - rval->obufsize = size; - } - return rval; -} - -void -rpcUdpXactDestroy(RpcUdpXact xact) -{ -int i = xact->obuf.xid & XACT_HASH_MSK; - -#if (DEBUG) & DEBUG_TRACE_XACT - fprintf(stderr,"RPCIO: removing index %i, val %x\n",i,xact); -#endif - - ASSERT( xactHashTbl[i]==xact ); - - MU_LOCK(hlock); - xactHashTbl[i]=0; - MU_UNLOCK(hlock); - - bufFree(&xact->ibuf); - - XDR_DESTROY(&xact->xdrs); - MY_FREE(xact); -} - - - -/* Send a transaction, i.e. enqueue it to the - * RPC daemon who will actually send it. - */ -enum clnt_stat -rpcUdpSend( - RpcUdpXact xact, - RpcUdpServer srvr, - struct timeval *timeout, - u_long proc, - xdrproc_t xres, caddr_t pres, - xdrproc_t xargs, caddr_t pargs, - ... - ) -{ -register XDR *xdrs; -unsigned long ms; -va_list ap; - - va_start(ap,pargs); - - if (!timeout) - timeout = RPCIOD_DEFAULT_TIMEOUT; - - ms = 1000 * timeout->tv_sec + timeout->tv_usec/1000; - - xact->lifetime = ms * ticksPerSec / 1000; -#if (DEBUG) & DEBUG_TIMEOUT - { - static int once=0; - if (!once++) { - fprintf(stderr, - "Initial lifetime: %i (ticks)\n", - xact->lifetime); - } - } -#endif - - xact->tolive = xact->lifetime; - - xact->xres = xres; - xact->pres = pres; - xact->server = srvr; - - xdrs = &xact->xdrs; - xdrs->x_op = XDR_ENCODE; - /* increment transaction ID */ - xact->obuf.xid += XACT_HASHS; - XDR_SETPOS(xdrs, xact->xdrpos); - if ( !XDR_PUTLONG(xdrs,&proc) || !locked_marshal(srvr, xdrs) || - !xargs(xdrs, pargs) ) { - va_end(ap); - return(xact->status.re_status=RPC_CANTENCODEARGS); - } - while ((xargs=va_arg(ap,xdrproc_t))) { - if (!xargs(xdrs, va_arg(ap,caddr_t))) - va_end(ap); - return(xact->status.re_status=RPC_CANTENCODEARGS); - } - - va_end(ap); - - rtems_task_ident(RTEMS_SELF, RTEMS_WHO_AM_I, &xact->requestor); - if ( rtems_message_queue_send( msgQ, &xact, sizeof(xact)) ) { - return RPC_CANTSEND; - } - /* wakeup the rpciod */ - ASSERT( RTEMS_SUCCESSFUL==rtems_event_send(rpciod, RPCIOD_TX_EVENT) ); - - return RPC_SUCCESS; -} - -/* Block for the RPC reply to an outstanding - * transaction. - * The caller is woken by the RPC daemon either - * upon reception of the reply or on timeout. - */ -enum clnt_stat -rpcUdpRcv(RpcUdpXact xact) -{ -int refresh; -XDR reply_xdrs; -struct rpc_msg reply_msg; -rtems_event_set gotEvents; - - refresh = 0; - - do { - - /* block for the reply */ - ASSERT( RTEMS_SUCCESSFUL == - rtems_event_receive( - RTEMS_RPC_EVENT, - RTEMS_WAIT | RTEMS_EVENT_ANY, - RTEMS_NO_TIMEOUT, - &gotEvents) ); - - if (xact->status.re_status) { -#ifdef MBUF_RX - /* add paranoia */ - ASSERT( !xact->ibuf ); -#endif - return xact->status.re_status; - } - -#ifdef MBUF_RX - xdrmbuf_create(&reply_xdrs, xact->ibuf, XDR_DECODE); -#else - xdrmem_create(&reply_xdrs, xact->ibuf->buf, xact->ibufsize, XDR_DECODE); -#endif - - reply_msg.acpted_rply.ar_verf = _null_auth; - reply_msg.acpted_rply.ar_results.where = xact->pres; - reply_msg.acpted_rply.ar_results.proc = xact->xres; - - if (xdr_replymsg(&reply_xdrs, &reply_msg)) { - /* OK */ - _seterr_reply(&reply_msg, &xact->status); - if (RPC_SUCCESS == xact->status.re_status) { - if ( !locked_validate(xact->server, - &reply_msg.acpted_rply.ar_verf) ) { - xact->status.re_status = RPC_AUTHERROR; - xact->status.re_why = AUTH_INVALIDRESP; - } - if (reply_msg.acpted_rply.ar_verf.oa_base) { - reply_xdrs.x_op = XDR_FREE; - xdr_opaque_auth(&reply_xdrs, &reply_msg.acpted_rply.ar_verf); - } - refresh = 0; - } else { - /* should we try to refresh our credentials ? */ - if ( !refresh ) { - /* had never tried before */ - refresh = RPCIOD_REFRESH; - } - } - } else { - reply_xdrs.x_op = XDR_FREE; - xdr_replymsg(&reply_xdrs, &reply_msg); - xact->status.re_status = RPC_CANTDECODERES; - } - XDR_DESTROY(&reply_xdrs); - - bufFree(&xact->ibuf); - -#ifndef MBUF_RX - xact->ibufsize = 0; -#endif - - if (refresh && locked_refresh(xact->server)) { - rtems_task_ident(RTEMS_SELF, RTEMS_WHO_AM_I, &xact->requestor); - if ( rtems_message_queue_send(msgQ, &xact, sizeof(xact)) ) { - return RPC_CANTSEND; - } - /* wakeup the rpciod */ - fprintf(stderr,"RPCIO INFO: refreshing my AUTH\n"); - ASSERT( RTEMS_SUCCESSFUL==rtems_event_send(rpciod, RPCIOD_TX_EVENT) ); - } - - } while ( 0 && refresh-- > 0 ); - - return xact->status.re_status; -} - - -/* On RTEMS, I'm told to avoid select(); this seems to - * be more efficient - */ -static void -rxWakeupCB(struct socket *sock, caddr_t arg) -{ -rtems_event_send((rtems_id)arg, RPCIOD_RX_EVENT); -} - -int -rpcUdpInit(void) -{ -int noblock = 1; -struct sockwakeup wkup; - - fprintf(stderr,"This is RTEMS-RPCIOD Release $Name$\n"); - fprintf(stderr,"($Id$)\n\n"); - fprintf(stderr,"Till Straumann, Stanford/SLAC/SSRL 2002\n"); - fprintf(stderr,"See LICENSE file for licensing info\n"); - - if (ourSock < 0) { - ourSock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (ourSock>=0) { - bindresvport(ourSock,(struct sockaddr_in*)0); - assert( 0==ioctl(ourSock, FIONBIO, (char*)&noblock) ); - /* assume nobody tampers with the clock !! */ - assert( RTEMS_SUCCESSFUL == rtems_clock_get( - RTEMS_CLOCK_GET_TICKS_PER_SECOND, - &ticksPerSec)); - MU_CREAT( &hlock ); - MU_CREAT( &llock ); - - assert( RTEMS_SUCCESSFUL == rtems_task_create( - rtems_build_name('R','P','C','d'), - RPCIOD_PRIO, - RPCIOD_STACK, - RTEMS_DEFAULT_MODES, - /* fprintf saves/restores FP registers on PPC :-( */ - RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, - &rpciod) ); - wkup.sw_pfn = rxWakeupCB; - wkup.sw_arg = (caddr_t)rpciod; - assert( 0==setsockopt(ourSock, SOL_SOCKET, SO_RCVWAKEUP, &wkup, sizeof(wkup)) ); - assert( RTEMS_SUCCESSFUL == rtems_message_queue_create( - rtems_build_name('R','P','C','q'), - RPCIOD_QDEPTH, - sizeof(RpcUdpXact), - RTEMS_DEFAULT_ATTRIBUTES, - &msgQ) ); - assert( RTEMS_SUCCESSFUL == rtems_task_start( - rpciod, - rpcio_daemon, - 0 ) ); - - } else { - return -1; - } - } - return 0; -} - -int -rpcUdpCleanup(void) -{ - rtems_semaphore_create( - rtems_build_name('R','P','C','f'), - 0, - RTEMS_DEFAULT_ATTRIBUTES, - 0, - &fini); - rtems_event_send(rpciod, RPCIOD_KILL_EVENT); - /* synchronize with daemon */ - rtems_semaphore_obtain(fini, RTEMS_WAIT, 5*ticksPerSec); - /* if the message queue is still there, something went wrong */ - if (!msgQ) { - rtems_task_delete(rpciod); - } - rtems_semaphore_delete(fini); - return (msgQ !=0); -} - -/* Another API - simpler but less efficient. - * For each RPCall, a server and a Xact - * are created and destroyed on the fly. - * - * This should be used for infrequent calls - * (e.g. a NFS mount request). - * - * This is roughly compatible with the original - * clnt_call() etc. API - but it uses our - * daemon and is fully reentrant. - */ -enum clnt_stat -rpcUdpClntCreate( - struct sockaddr_in *psaddr, - int prog, - int vers, - u_long uid, - u_long gid, - RpcUdpClnt *pclnt -) -{ -RpcUdpXact x; -RpcUdpServer s; -enum clnt_stat err; - - if ( RPC_SUCCESS != (err=rpcUdpServerCreate(psaddr, prog, vers, uid, gid, &s)) ) - return err; - - if ( !(x=rpcUdpXactCreate(prog, vers, UDPMSGSIZE)) ) { - rpcUdpServerDestroy(s); - return RPC_FAILED; - } - /* TODO: could maintain a server cache */ - - x->server = s; - - *pclnt = x; - - return RPC_SUCCESS; -} - -void -rpcUdpClntDestroy(RpcUdpClnt xact) -{ - rpcUdpServerDestroy(xact->server); - rpcUdpXactDestroy(xact); -} - -enum clnt_stat -rpcUdpClntCall( - RpcUdpClnt xact, - u_long proc, - XdrProcT xargs, - CaddrT pargs, - XdrProcT xres, - CaddrT pres, - struct timeval *timeout - ) -{ -enum clnt_stat stat; - - if ( (stat = rpcUdpSend(xact, xact->server, timeout, proc, - xres, pres, - xargs, pargs, - 0)) ) { - fprintf(stderr,"RPCIO Send failed: %i\n",stat); - return stat; - } - return rpcUdpRcv(xact); -} - -/* a yet simpler interface */ -enum clnt_stat -rpcUdpCallRp( - struct sockaddr_in *psrvr, - u_long prog, - u_long vers, - u_long proc, - XdrProcT xargs, - CaddrT pargs, - XdrProcT xres, - CaddrT pres, - u_long uid, /* RPCIO_DEFAULT_ID picks default */ - u_long gid, /* RPCIO_DEFAULT_ID picks default */ - struct timeval *timeout /* NULL picks default */ -) -{ -RpcUdpClnt clp; -enum clnt_stat stat; - - stat = rpcUdpClntCreate( - psrvr, - prog, - vers, - uid, - gid, - &clp); - - if ( RPC_SUCCESS != stat ) - return stat; - - stat = rpcUdpClntCall( - clp, - proc, - xargs, pargs, - xres, pres, - timeout); - - rpcUdpClntDestroy(clp); - - return stat; -} - -/* linked list primitives */ -static void -nodeXtract(ListNode n) -{ - if (n->prev) - n->prev->next = n->next; - if (n->next) - n->next->prev = n->prev; - n->next = n->prev = 0; -} - -static void -nodeAppend(ListNode l, ListNode n) -{ - if ( (n->next = l->next) ) - n->next->prev = n; - l->next = n; - n->prev = l; - -} - -/* this code does the work */ -static void -rpcio_daemon(rtems_task_argument arg) -{ -rtems_status_code stat; -RpcUdpXact xact; -RpcUdpServer srv; -rtems_interval next_retrans, then, unow; -long now; /* need to do signed comparison with age! */ -rtems_event_set events; -ListNode newList; -rtems_unsigned32 size; -rtems_id q = 0; -ListNodeRec listHead = {0}; -unsigned long epoch = RPCIOD_EPOCH_SECS * ticksPerSec; -unsigned long max_period = RPCIOD_RETX_CAP_S * ticksPerSec; - - assert( RTEMS_SUCCESSFUL == rtems_clock_get( - RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, - &then) ); - - for (next_retrans = epoch;;) { - - if ( RTEMS_SUCCESSFUL != - (stat = rtems_event_receive( - RPCIOD_RX_EVENT | RPCIOD_TX_EVENT | RPCIOD_KILL_EVENT, - RTEMS_WAIT | RTEMS_EVENT_ANY, - next_retrans, - &events)) ) { - ASSERT( RTEMS_TIMEOUT == stat ); - events = 0; - } - - if (events & RPCIOD_KILL_EVENT) { - int i; - -#if (DEBUG) & DEBUG_EVENTS - fprintf(stderr,"RPCIO: got KILL event\n"); -#endif - - MU_LOCK(hlock); - for (i=XACT_HASHS-1; i>=0; i--) { - if (xactHashTbl[i]) { - break; - } - } - if (i<0) { - /* prevent them from creating and enqueueing more messages */ - q=msgQ; - /* messages queued after we executed this assignment will fail */ - msgQ=0; - } - MU_UNLOCK(hlock); - if (i>=0) { - fprintf(stderr,"RPCIO There are still transactions circulating; I refuse to go away\n"); - fprintf(stderr,"(1st in slot %i)\n",i); - rtems_semaphore_release(fini); - } else { - break; - } - } - - ASSERT( RTEMS_SUCCESSFUL == rtems_clock_get( - RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, - &unow ) ); - - /* measure everything relative to then to protect against - * rollover - */ - now = unow - then; - - /* NOTE: we don't lock the hash table while we are operating - * on transactions; the paradigm is that we 'own' a particular - * transaction (and hence it's hash table slot) from the - * time the xact was put into the message queue until we - * wake up the requestor. - */ - - if (RPCIOD_RX_EVENT & events) { - -#if (DEBUG) & DEBUG_EVENTS - fprintf(stderr,"RPCIO: got RX event\n"); -#endif - - while ((xact=sockRcv())) { - - /* extract from the retransmission list */ - nodeXtract(&xact->node); - - /* change the ID - there might already be - * a retransmission on the way. When it's - * reply arrives we must not find it's ID - * in the hashtable - */ - xact->obuf.xid += XACT_HASHS; - - xact->status.re_status = RPC_SUCCESS; - - /* calculate roundtrip ticks */ - xact->trip = now - xact->trip; - - srv = xact->server; - - /* adjust the server's retry period */ - { - register TimeoutT rtry = srv->retry_period; - register TimeoutT trip = xact->trip; - - ASSERT( trip >= 0 ); - - if ( 0==trip ) - trip = 1; - - /* retry_new = 0.75*retry_old + 0.25 * 8 * roundrip */ - rtry = (3*rtry + (trip << 3)) >> 2; - - if ( rtry > max_period ) - rtry = max_period; - - srv->retry_period = rtry; - } - - /* wakeup requestor */ - rtems_event_send(xact->requestor, RTEMS_RPC_EVENT); - } - } - - if (RPCIOD_TX_EVENT & events) { - -#if (DEBUG) & DEBUG_EVENTS - fprintf(stderr,"RPCIO: got TX event\n"); -#endif - - while (RTEMS_SUCCESSFUL == rtems_message_queue_receive( - msgQ, - &xact, - &size, - RTEMS_NO_WAIT, - RTEMS_NO_TIMEOUT)) { - /* put to the head of timeout q */ - nodeAppend(&listHead, &xact->node); - - xact->age = now; - xact->trip = FIRST_ATTEMPT; - } - } - - - /* work the timeout q */ - newList = 0; - for ( xact=(RpcUdpXact)listHead.next; - xact && xact->age <= now; - xact=(RpcUdpXact)listHead.next ) { - - /* extract from the list */ - nodeXtract(&xact->node); - - srv = xact->server; - - if (xact->tolive < 0) { - /* this one timed out */ - xact->status.re_errno = ETIMEDOUT; - xact->status.re_status = RPC_TIMEDOUT; - - srv->timeouts++; - -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr,"RPCIO XACT timed out; waking up requestor\n"); -#endif - if ( rtems_event_send(xact->requestor, RTEMS_RPC_EVENT) ) { - rtems_panic("RPCIO PANIC file %s line: %i, requestor id was 0x%08x", - __FILE__, - __LINE__, - xact->requestor); - } - - } else { - int len; - - len = (int)XDR_GETPOS(&xact->xdrs); - -#ifdef MBUF_TX - xact->refcnt = 1; /* sendto itself */ -#endif - if ( len != SENDTO( ourSock, - xact->obuf.buf, - len, - 0, - (struct sockaddr*) &srv->addr, - sizeof(srv->addr) -#ifdef MBUF_TX - , xact, - paranoia_free, - paranoia_ref -#endif - ) ) { - - xact->status.re_errno = errno; - xact->status.re_status = RPC_CANTSEND; - srv->errors++; - - /* wakeup requestor */ - fprintf(stderr,"RPCIO: SEND failure\n"); - ASSERT( RTEMS_SUCCESSFUL == - rtems_event_send(xact->requestor, RTEMS_RPC_EVENT) ); - - } else { - /* send successful; calculate retransmission time - * and enqueue to temporary list - */ - if (FIRST_ATTEMPT != xact->trip) { -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr, - "timed out; tolive is %i (ticks), retry period is %i (ticks)\n", - xact->tolive, - srv->retry_period); -#endif - /* this is a real retry; we backup - * the server's retry interval - */ - if ( srv->retry_period < max_period ) { - - /* If multiple transactions for this server - * fail (e.g. because it died) this will - * back-off very agressively (doubling - * the retransmission period for every - * timed out transaction up to the CAP limit) - * which is desirable - single packet failure - * is treated more gracefully by this algorithm. - */ - - srv->retry_period<<=1; -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr, - "adjusted to; retry period %i\n", - srv->retry_period); -#endif - } else { - /* never wait longer than RPCIOD_RETX_CAP_S seconds */ - fprintf(stderr, - "RPCIO: server '%s' not responding - still trying\n", - srv->name); - } - if ( 0 == ++srv->retrans % 1000) { - fprintf(stderr, - "RPCIO - statistics: already %li retries to server %s\n", - srv->retrans, - srv->name); - } - } else { - srv->requests++; - } - xact->trip = now; - xact->age = now + srv->retry_period; - xact->tolive -= srv->retry_period; - /* enqueue to the list of newly sent transactions */ - xact->node.next = newList; - newList = &xact->node; -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr, - "XACT (0x%08x) age is 0x%x, now: 0x%x\n", - xact, - xact->age, - now); -#endif - } - } - } - - /* insert the newly sent transactions into the - * sorted retransmission list - */ - for (; (xact = (RpcUdpXact)newList); ) { - register ListNode p,n; - newList = newList->next; - for ( p=&listHead; (n=p->next) && xact->age > ((RpcUdpXact)n)->age; p=n ) - /* nothing else to do */; - nodeAppend(p, &xact->node); - } - - if (now > epoch) { - /* every now and then, readjust the epoch */ - register ListNode n; - then += now; - for (n=listHead.next; n; n=n->next) { - /* readjust outstanding time intervals subject to the - * condition that the 'absolute' time must remain - * the same. 'age' and 'trip' are measured with - * respect to 'then' - hence: - * - * abs_age == old_age + old_then == new_age + new_then - * - * ==> new_age = old_age + old_then - new_then == old_age - 'now' - */ - ((RpcUdpXact)n)->age -= now; - ((RpcUdpXact)n)->trip -= now; -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr, - "readjusted XACT (0x%08x); age is 0x%x, trip: 0x%x now: 0x%x\n", - (RpcUdpXact)n, - ((RpcUdpXact)n)->trip, - ((RpcUdpXact)n)->age, - now); -#endif - } - now = 0; - } - - next_retrans = listHead.next ? - ((RpcUdpXact)listHead.next)->age - now : - epoch; /* make sure we don't miss updating the epoch */ -#if (DEBUG) & DEBUG_TIMEOUT - fprintf(stderr,"RPCIO: next timeout is %x\n",next_retrans); -#endif - } - /* close our socket; shut down the receiver */ - close(ourSock); - -#if 0 /* if we get here, no transactions exist, hence there can be none - * in the queue whatsoever - */ - /* flush the message queue */ - while (RTEMS_SUCCESSFUL == rtems_message_queue_receive( - q, - &xact, - &size, - RTEMS_NO_WAIT, - RTEMS_NO_TIMEOUT)) { - /* TODO enque xact */ - } - - /* flush all outstanding transactions */ - - for (xact=((RpcUdpXact)listHead.next); xact; xact=((RpcUdpXact)xact->node.next)) { - xact->status.re_status = RPC_TIMEDOUT; - rtems_event_send(xact->requestor, RTEMS_RPC_EVENT); - } -#endif - - rtems_message_queue_delete(q); - - MU_DESTROY(hlock); - - fprintf(stderr,"RPC daemon exited...\n"); - - rtems_semaphore_release(fini); - rtems_task_suspend(RTEMS_SELF); -} - - -/* support for transaction 'pools'. A number of XACT objects - * is always kept around. The initial number is 0 but it - * is allowed to grow up to a maximum. - * If the need grows beyond the maximum, behavior depends: - * Users can either block until a transaction becomes available, - * they can create a new XACT on the fly or get an error - * if no free XACT is available from the pool. - */ - -RpcUdpXactPool -rpcUdpXactPoolCreate( - int prog, int version, - int xactsize, int poolsize) -{ -RpcUdpXactPool rval = MY_MALLOC(sizeof(*rval)); - - ASSERT( rval && - RTEMS_SUCCESSFUL == rtems_message_queue_create( - rtems_build_name('R','P','C','p'), - poolsize, - sizeof(RpcUdpXact), - RTEMS_DEFAULT_ATTRIBUTES, - &rval->box) ); - rval->prog = prog; - rval->version = version; - rval->xactSize = xactsize; - return rval; -} - -void -rpcUdpXactPoolDestroy(RpcUdpXactPool pool) -{ -RpcUdpXact xact; - - while ((xact = rpcUdpXactPoolGet(pool, XactGetFail))) { - rpcUdpXactDestroy(xact); - } - rtems_message_queue_delete(pool->box); - MY_FREE(pool); -} - -RpcUdpXact -rpcUdpXactPoolGet(RpcUdpXactPool pool, XactPoolGetMode mode) -{ -RpcUdpXact xact = 0; -rtems_unsigned32 size; - - if (RTEMS_SUCCESSFUL != rtems_message_queue_receive( - pool->box, - &xact, - &size, - XactGetWait == mode ? - RTEMS_WAIT : RTEMS_NO_WAIT, - RTEMS_NO_TIMEOUT)) { - - /* nothing found in box; should we create a new one ? */ - - xact = (XactGetCreate == mode) ? - rpcUdpXactCreate( - pool->prog, - pool->version, - pool->xactSize) : 0 ; - if (xact) - xact->pool = pool; - - } - return xact; -} - -void -rpcUdpXactPoolPut(RpcUdpXact xact) -{ -RpcUdpXactPool pool; - ASSERT( pool=xact->pool ); - if (RTEMS_SUCCESSFUL != rtems_message_queue_send( - pool->box, - &xact, - sizeof(xact))) - rpcUdpXactDestroy(xact); -} - -#ifdef MBUF_RX - -/* WORKAROUND: include sys/mbuf.h (or other bsdnet headers) only - * _after_ using malloc()/free() & friends because - * the RTEMS/BSDNET headers redefine those :-( - */ - -#define KERNEL -#include - -ssize_t -recv_mbuf_from(int s, struct mbuf **ppm, long len, struct sockaddr *fromaddr, int *fromlen); - -static void -bufFree(struct mbuf **m) -{ - if (*m) { - rtems_bsdnet_semaphore_obtain(); - m_freem(*m); - rtems_bsdnet_semaphore_release(); - *m = 0; - } -} -#endif - -#ifdef MBUF_TX -static void -paranoia_free(caddr_t closure, u_int size) -{ -#if (DEBUG) -RpcUdpXact xact = (RpcUdpXact)closure; -int len = (int)XDR_GETPOS(&xact->xdrs); - - ASSERT( --xact->refcnt >= 0 && size == len ); -#endif -} - -static void -paranoia_ref (caddr_t closure, u_int size) -{ -#if (DEBUG) -RpcUdpXact xact = (RpcUdpXact)closure; -int len = (int)XDR_GETPOS(&xact->xdrs); - ASSERT( size == len ); - xact->refcnt++; -#endif -} -#endif - -/* receive from a socket and find - * the transaction corresponding to the - * transaction ID received in the server - * reply. - * - * The semantics of the 'pibuf' pointer are - * as follows: - * - * MBUF_RX: - * - */ - -#define RPCIOD_RXBUFSZ UDPMSGSIZE - -static RpcUdpXact -sockRcv(void) -{ -int len,i; -u_long xid; -struct sockaddr_in fromAddr; -int fromLen = sizeof(fromAddr); -RxBuf ibuf = 0; -RpcUdpXact xact = 0; - - do { - - /* rcv_mbuf() and recvfrom() differ in that the - * former allocates buffers and passes them back - * to us whereas the latter requires us to provide - * buffer space. - * Hence, in the first case whe have to make sure - * no old buffer is leaked - in the second case, - * we might well re-use an old buffer but must - * make sure we have one allocated - */ -#ifdef MBUF_RX - if (ibuf) - bufFree(&ibuf); - - len = recv_mbuf_from( - ourSock, - &ibuf, - RPCIOD_RXBUFSZ, - (struct sockaddr*)&fromAddr, - &fromLen); -#else - if ( !ibuf ) - ibuf = (RpcBuf)MY_MALLOC(RPCIOD_RXBUFSZ); - if ( !ibuf ) - goto cleanup; /* no memory - drop this message */ - - len = recvfrom(ourSock, - ibuf->buf, - RPCIOD_RXBUFSZ, - 0, - (struct sockaddr*)&fromAddr, - &fromLen); -#endif - - if (len <= 0) { - if (EAGAIN != errno) - fprintf(stderr,"RECV failed: %s\n",strerror(errno)); - goto cleanup; - } - -#if (DEBUG) & DEBUG_PACKLOSS - if ( (unsigned)rand() < DEBUG_PACKLOSS_FRACT ) { - /* lose packets once in a while */ - static int xxx = 0; - if ( ++xxx % 16 == 0 ) - fprintf(stderr,"DEBUG: dropped %i packets, so far...\n",xxx); - if ( ibuf ) - bufFree( &ibuf ); - continue; - } -#endif - - i = (xid=XID(ibuf)) & XACT_HASH_MSK; - - if ( !(xact=xactHashTbl[i]) || - xact->obuf.xid != xid || - xact->server->addr.sin_addr.s_addr != fromAddr.sin_addr.s_addr || - xact->server->addr.sin_port != fromAddr.sin_port ) { - - if (xact) { - if (xact->server->addr.sin_addr.s_addr == fromAddr.sin_addr.s_addr && - xact->server->addr.sin_port == fromAddr.sin_port && - ( xact->obuf.xid == xid + XACT_HASHS || - xact->obuf.xid == xid + 2*XACT_HASHS ) - ) { -#ifndef DEBUG /* don't complain if it's just a late arrival of a retry */ - fprintf(stderr,"RPCIO - FYI sockRcv(): dropping late/redundant retry answer\n"); -#endif - } else { - fprintf(stderr,"RPCIO WARNING sockRcv(): transaction mismatch\n"); - fprintf(stderr,"xact: xid 0x%08lx -- got 0x%08lx\n", - xact->obuf.xid, xid); - fprintf(stderr,"xact: addr 0x%08lx -- got 0x%08lx\n", - xact->server->addr.sin_addr.s_addr, - fromAddr.sin_addr.s_addr); - fprintf(stderr,"xact: port 0x%08x -- got 0x%08x\n", - xact->server->addr.sin_port, - fromAddr.sin_port); - } - } else { - fprintf(stderr, - "RPCIO WARNING sockRcv(): got xid 0x%08lx but its slot is empty\n", - xid); - } - /* forget about this one and try again */ - xact = 0; - } - - } while ( !xact ); - - xact->ibuf = ibuf; -#ifndef MBUF_RX - xact->ibufsize = RPCIOD_RXBUFSZ; -#endif - - return xact; - -cleanup: - - bufFree(&ibuf); - - return 0; -} - - -#include -/* double check the event configuration; should probably globally - * manage system events!! - * We do this at the end of the file for the same reason we had - * included mbuf.h only a couple of lines above - see comment up - * there... - */ -#if RTEMS_RPC_EVENT & SOSLEEP_EVENT & SBWAIT_EVENT & NETISR_EVENTS -#error ILLEGAL EVENT CONFIGURATION -#endif diff --git a/rtemsNfs-1.1/src/rpcio.h b/rtemsNfs-1.1/src/rpcio.h deleted file mode 100644 index 922bc0d..0000000 --- a/rtemsNfs-1.1/src/rpcio.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef RPCIO_H -#define RPCIO_H -/* $Id$ */ - -/* A multihreaded RPC/UDP multiplexor */ - -/* Author: Till Straumann, , 2002 */ - -/* - * Copyright 2002, Stanford University and - * Till Straumann - * - * Stanford Notice - * *************** - * - * Acknowledgement of sponsorship - * * * * * * * * * * * * * * * * * - * This software was produced by the Stanford Linear Accelerator Center, - * Stanford University, under Contract DE-AC03-76SFO0515 with the Department - * of Energy. - * - * Government disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, - * or assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately - * owned rights. - * - * Stanford disclaimer of liability - * - - - - - - - - - - - - - - - - - - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * This product is subject to the EPICS open license - * - - - - - - - - - - - - - - - - - - - - - - - - - - * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php - * for more information. - * - * Maintenance of notice - * - - - - - - - - - - - - * In the interest of clarity regarding the origin and status of this - * software, Stanford University requests that any recipient of it maintain - * this notice affixed to any distribution by the recipient that contains a - * copy or derivative of this software. - */ - - -#ifdef __rtems -#include -#endif - -#include -#include -#include -#include -#include - -typedef struct RpcUdpServerRec_ *RpcUdpServer; -typedef struct RpcUdpXactRec_ *RpcUdpXact; - -typedef RpcUdpXact RpcUdpClnt; - -#define RPCIOD_DEFAULT_ID 0xdef10000 - -int -rpcUdpInit(void); - -enum clnt_stat -rpcUdpServerCreate( - struct sockaddr_in *paddr, - int prog, - int vers, - u_long uid, /* RPCIO_DEFAULT_ID picks default */ - u_long gid, /* RPCIO_DEFAULT_ID picks default */ - RpcUdpServer *pclnt /* new server is returned here */ - ); - - -void -rpcUdpServerDestroy(RpcUdpServer s); - -/* Dump statistics to a file (stdout if NULL); - * returns 0 for convenience - */ -int -rpcUdpStats(FILE *f); - -enum clnt_stat -rpcUdpClntCreate( - struct sockaddr_in *psaddr, - int prog, - int vers, - u_long uid, /* RPCIO_DEFAULT_ID picks default */ - u_long gid, /* RPCIO_DEFAULT_ID picks default */ - RpcUdpClnt *pclnt /* new client is returned here */ - ); - -void -RpcUdpClntDestroy(RpcUdpClnt clnt); - -/* mute compiler warnings */ -typedef void *XdrProcT; -typedef void *CaddrT; - -enum clnt_stat -rpcUdpClntCall( - RpcUdpClnt clnt, - u_long proc, - XdrProcT xargs, - CaddrT pargs, - XdrProcT xres, - CaddrT pres, - struct timeval *timeout /* optional timeout; maybe NULL to pick default */ - ); - -RpcUdpXact -rpcUdpXactCreate( - u_long program, - u_long version, - u_long size - ); - -void -rpcUdpXactDestroy( - RpcUdpXact xact - ); - -/* send a transaction */ -enum clnt_stat -rpcUdpSend( - RpcUdpXact xact, - RpcUdpServer srvr, - struct timeval *timeout, /* maybe NULL to pick default */ - u_long proc, - xdrproc_t xres, - caddr_t pres, - xdrproc_t xargs, - caddr_t pargs, - ... /* 0 terminated xdrproc/pobj additional argument list */ - ); - -/* wait for a transaction to complete */ -enum clnt_stat -rpcUdpRcv(RpcUdpXact xact); - -/* a yet simpler interface */ -enum clnt_stat -rpcUdpCallRp( - struct sockaddr_in *pserver_addr, - u_long prog, - u_long vers, - u_long proc, - XdrProcT xargs, - CaddrT pargs, - XdrProcT xres, - CaddrT pres, - u_long uid, /* RPCIO_DEFAULT_ID picks default */ - u_long gid, /* RPCIO_DEFAULT_ID picks default */ - struct timeval *timeout /* NULL picks default */ -); - - -/* manage pools of transactions */ - -/* A pool of transactions. The idea is not to malloc/free them - * all the time but keep a limited number around in a 'pool'. - * Users who need a XACT may get it from the pool and put it back - * when done. - * The pool is implemented by RTEMS message queues who manage - * the required task synchronization. - * A requestor has different options if the pool is empty: - * - it can wait (block) for a XACT to become available - * - it can get an error status - * - or it can malloc an extra XACT from the heap which - * will eventually be released. - */ - -typedef struct RpcUdpXactPoolRec_ *RpcUdpXactPool; - -/* NOTE: the pool is empty initially, must get messages (in - * GetCreate mode - */ -RpcUdpXactPool -rpcUdpXactPoolCreate( - int prog, int version, - int xactsize, int poolsize); - -void -rpcUdpXactPoolDestroy(RpcUdpXactPool pool); - -typedef enum { - XactGetFail, /* call fails if no transaction available */ - XactGetWait, /* call blocks until transaction available */ - XactGetCreate /* a new transaction is allocated (and freed when put back to the pool */ -} XactPoolGetMode; - -RpcUdpXact -rpcUdpXactPoolGet(RpcUdpXactPool pool, XactPoolGetMode mode); - -void -rpcUdpXactPoolPut(RpcUdpXact xact); - -#endif diff --git a/rtemsNfs-1.1/src/rpcio.modini.c b/rtemsNfs-1.1/src/rpcio.modini.c deleted file mode 100644 index 7773b3d..0000000 --- a/rtemsNfs-1.1/src/rpcio.modini.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "librtemsNfs.h" -/* CEXP module support (magic init) */ -void -_cexpModuleInitialize(void *mod) -{ - rpcUdpInit(); -} - -int -_cexpModuleFinalize(void *mod) -{ - return rpcUdpCleanup(); -} - - diff --git a/rtemsNfs-1.1/src/sock_mbuf.c b/rtemsNfs-1.1/src/sock_mbuf.c deleted file mode 100644 index 70c09d6..0000000 --- a/rtemsNfs-1.1/src/sock_mbuf.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * $Id$ - * - * NOTE: - * This is derived from libnetworking/rtems/rtems_syscall.c - * - * RTEMS/libnetworking LICENSING restrictions may apply - * - * Author (modifications only): - * Copyright: 2002, Stanford University and - * Till Straumann, - * Licensing: 'LICENSE.NET' file in the RTEMS top source directory - * for more information. - */ - -/* -The RTEMS TCP/IP stack is a port of the FreeBSD TCP/IP stack. The following -copyright and licensing information applies to this code. - -This code is found under the c/src/libnetworking directory but does not -constitute the entire contents of that subdirectory. - -============================================================================= - -Copyright (c) 1980, 1983, 1988, 1993 - The Regents of the University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. All advertising materials mentioning features or use of this software - must display the following acknowledgment: - This product includes software developed by the University of - California, Berkeley and its contributors. -4. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -- -Portions Copyright (c) 1993 by Digital Equipment Corporation. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies, and that -the name of Digital Equipment Corporation not be used in advertising or -publicity pertaining to distribution of the document or software without -specific, written prior permission. - -THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT -CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -============================================================================= -*/ - - -#include -#include -#include - -#include -#include -#include - -#define KERNEL -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct socket *rtems_bsdnet_fdToSocket(int fd); - -/* - * Package system call argument into mbuf. - * - * (unfortunately, the original is not public) - */ -static int -sockaddrtombuf (struct mbuf **mp, const struct sockaddr *buf, int buflen) -{ -struct mbuf *m; -struct sockaddr *sa; - - if ((u_int)buflen > MLEN) - return (EINVAL); - - rtems_bsdnet_semaphore_obtain(); - m = m_get(M_WAIT, MT_SONAME); - rtems_bsdnet_semaphore_release(); - - if (m == NULL) - return (ENOBUFS); - m->m_len = buflen; - memcpy (mtod(m, caddr_t), buf, buflen); - *mp = m; - sa = mtod(m, struct sockaddr *); - sa->sa_len = buflen; - - return 0; -} - -static void -dummyproc(caddr_t ext_buf, u_int ext_size) -{ -} - -/* - * send data by simply allocating an MBUF packet - * header and pointing it to our data region. - * - * Optionally, the caller may supply 'reference' - * and 'free' procs. (The latter may call the - * user back once the networking stack has - * released the buffer). - * - * The callbacks are provided with the 'closure' - * pointer and the 'buflen' argument. - */ -ssize_t -sendto_nocpy ( - int s, - const void *buf, size_t buflen, - int flags, - const struct sockaddr *toaddr, int tolen, - void *closure, - void (*freeproc)(caddr_t, u_int), - void (*refproc)(caddr_t, u_int) -) -{ - int error; - struct socket *so; - struct mbuf *to, *m; - int ret = -1; - - rtems_bsdnet_semaphore_obtain (); - if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { - rtems_bsdnet_semaphore_release (); - return -1; - } - - error = sockaddrtombuf (&to, toaddr, tolen); - if (error) { - errno = error; - rtems_bsdnet_semaphore_release (); - return -1; - } - - MGETHDR(m, M_WAIT, MT_DATA); - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = (struct ifnet *) 0; - - m->m_flags |= M_EXT; - m->m_ext.ext_buf = closure ? closure : (void*)buf; - m->m_ext.ext_size = buflen; - /* we _must_ supply non-null procs; otherwise, - * the kernel code assumes it's a mbuf cluster - */ - m->m_ext.ext_free = freeproc ? freeproc : dummyproc; - m->m_ext.ext_ref = refproc ? refproc : dummyproc; - m->m_pkthdr.len += buflen; - m->m_len = buflen; - m->m_data = (void*)buf; - - error = sosend (so, to, NULL, m, NULL, flags); - if (error) { - if (/*auio.uio_resid != len &&*/ (error == EINTR || error == EWOULDBLOCK)) - error = 0; - } - if (error) - errno = error; - else - ret = buflen; - if (to) - m_freem(to); - rtems_bsdnet_semaphore_release (); - return (ret); -} - - -/* - * receive data in an 'mbuf chain'. - * The chain must be released once the - * data has been extracted: - * - * rtems_bsdnet_semaphore_obtain(); - * m_freem(chain); - * rtems_bsdnet_semaphore_release(); - */ -ssize_t -recv_mbuf_from(int s, struct mbuf **ppm, long len, struct sockaddr *fromaddr, int *fromlen) -{ - int ret = -1; - int error; - struct uio auio; - struct socket *so; - struct mbuf *from = NULL; - - memset(&auio, 0, sizeof(auio)); - *ppm = 0; - - rtems_bsdnet_semaphore_obtain (); - if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { - rtems_bsdnet_semaphore_release (); - return -1; - } -/* auio.uio_iov = mp->msg_iov; - auio.uio_iovcnt = mp->msg_iovlen; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; -*/ - auio.uio_resid = len; - error = soreceive (so, &from, &auio, (struct mbuf **) ppm, - (struct mbuf **)NULL, - NULL); - if (error) { - if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) - error = 0; - } - if (error) { - errno = error; - } - else { - ret = len - auio.uio_resid; - if (fromaddr) { - len = *fromlen; - if ((len <= 0) || (from == NULL)) { - len = 0; - } - else { - if (len > from->m_len) - len = from->m_len; - memcpy (fromaddr, mtod(from, caddr_t), len); - } - *fromlen = len; - } - } - if (from) - m_freem (from); - if (error && *ppm) { - m_freem(*ppm); - *ppm = 0; - } - rtems_bsdnet_semaphore_release (); - return (ret); -} diff --git a/rtemsNfs-1.1/src/xdr_mbuf.c b/rtemsNfs-1.1/src/xdr_mbuf.c deleted file mode 100644 index 22f972d..0000000 --- a/rtemsNfs-1.1/src/xdr_mbuf.c +++ /dev/null @@ -1,534 +0,0 @@ -/* $Id$ */ - -/* xdr_mbuf is derived from xdr_mem */ - -/* Author (mbuf specifica): Till Straumann , 10/2002 */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr_mem.c,v 1.8 1999/08/28 00:02:56 peter Exp $"; -#endif - -/* - * xdr_mbuf, XDR implementation using mbuf buffers - * - * derived from: - * - * xdr_mem.h, XDR implementation using memory buffers. - * - * Copyright (C) 1984, Sun Microsystems, Inc. - * - * The MBUF stream is useful for BSDNET kernel (or RTEMS for that matter) - * use. - */ - -#include -#include -#include -#include - -#include - -#define TODO - -/* TODO remove: a hack because malloc is redefined */ -#ifdef TODO -static inline void * -my_malloc(size_t i) -{ - return malloc(i); -} - -static inline void -my_free(void *p) -{ - return free(p); -} -#endif - -#define DEBUG_ASSERT (1<<0) -#define DEBUG_VERB (1<<1) - -#define DEBUG DEBUG_ASSERT - -#define KERNEL -#include - -#include - -#if DEBUG & DEBUG_VERB || defined(TODO) -#include -#endif - -static bool_t xdrmbuf_getlong_aligned(); -static bool_t xdrmbuf_putlong_aligned(); -static bool_t xdrmbuf_getlong_unaligned(); -static bool_t xdrmbuf_putlong_unaligned(); -static bool_t xdrmbuf_getbytes(); -static bool_t xdrmbuf_putbytes(); -static u_int xdrmbuf_getpos(); /* XXX w/64-bit pointers, u_int not enough! */ -static bool_t xdrmbuf_setpos(); -static int32_t *xdrmbuf_inline_aligned(); -static int32_t *xdrmbuf_inline_unaligned(); -static void xdrmbuf_destroy(); - -static struct xdr_ops xdrmbuf_ops_aligned = { - xdrmbuf_getlong_aligned, - xdrmbuf_putlong_aligned, - xdrmbuf_getbytes, - xdrmbuf_putbytes, - xdrmbuf_getpos, - xdrmbuf_setpos, - xdrmbuf_inline_aligned, - xdrmbuf_destroy -}; - -static struct xdr_ops xdrmbuf_ops_unaligned = { - xdrmbuf_getlong_unaligned, - xdrmbuf_putlong_unaligned, - xdrmbuf_getbytes, - xdrmbuf_putbytes, - xdrmbuf_getpos, - xdrmbuf_setpos, - xdrmbuf_inline_unaligned, - xdrmbuf_destroy -}; - -typedef struct MBPrivateRec_ { - struct mbuf *mchain; - struct mbuf *mcurrent; - u_int pos; /* number of bytes contained in all MUBFS ahead - * of mcurrent - */ -} MBPrivateRec, *MBPrivate; - -/* NOTE: the stream position helper 'pos' - * must be managed by the caller! - */ -static inline void -xdrmbuf_setup(XDR *xdrs, struct mbuf *m) -{ -MBPrivate mbp = (MBPrivate)xdrs->x_base; - - mbp->mcurrent = m; - xdrs->x_private = mtod(m,caddr_t); - xdrs->x_handy = m->m_len; - xdrs->x_ops = ((size_t)xdrs->x_private & (sizeof(int32_t) - 1)) - ? &xdrmbuf_ops_unaligned : &xdrmbuf_ops_aligned; -} - -static struct mbuf * -xdrmbuf_next(XDR *xdrs) -{ -struct mbuf *rval; -MBPrivate mbp = (MBPrivate)xdrs->x_base; - - if (mbp->mcurrent) { - mbp->pos += mbp->mcurrent->m_len; - rval = mbp->mcurrent->m_next; - } else { - rval = 0; - } - - if (rval) { - xdrmbuf_setup(xdrs, rval); - } -#if DEBUG & DEBUG_VERB - else { - fprintf(stderr,"xdrmbuf: end of chain\n"); - } -#endif - - return rval; -} - -/* - * The procedure xdrmbuf_create initializes a stream descriptor for a - * memory buffer. - */ -void -xdrmbuf_create(XDR *xdrs, struct mbuf *mbuf, enum xdr_op op) -{ -MBPrivate mbp; - - xdrs->x_op = op; - assert( mbp = (MBPrivate)my_malloc(sizeof(*mbp)) ); - xdrs->x_base = (caddr_t) mbp; - - mbp->mchain = mbuf; - mbp->pos = 0; - -#if DEBUG & DEBUG_VERB - { - struct mbuf *mbf; - fprintf(stderr,"Dumping chain:\n"); - for (mbf = mbuf; mbf; mbf=mbf->m_next) { - int ii; - fprintf(stderr,"MBUF------------"); - for (ii=0; iim_len; ii++) { - fprintf(stderr,"%02x ",mtod(mbf,char*)[ii]); - if (ii%16==0) - fputc('\n',stderr); - } - fputc('\n',stderr); - } - } -#endif - - xdrmbuf_setup(xdrs, mbuf); -} - -static void -xdrmbuf_destroy(XDR *xdrs) -{ -MBPrivate mbp = (MBPrivate)xdrs->x_base; -#if 0 /* leave destroying the chain to the user */ -struct mbuf *m = mbp->mchain; - - rtems_bsdnet_semaphore_obtain(); - m_freem(m); - rtems_bsdnet_semaphore_release(); -#endif - - my_free(mbp); -} - -static bool_t -xdrmbuf_getlong_aligned(register XDR *xdrs, register long *lp) -{ - while ( (signed int)(xdrs->x_handy -= sizeof(int32_t)) < 0) { - if ((xdrs->x_handy += sizeof(int32_t)) == 0) { - /* handy was 0 on entry; request a new buffer. - * Coded this way, so the most frequently executed - * path needs only one comparison... - */ - if (!xdrmbuf_next(xdrs)) - return FALSE; - } else { - /* uh-oh an aligned long spread over two MBUFS ?? - * let the unaligned handler deal with this rare - * situation. - */ - return xdrmbuf_getlong_unaligned(xdrs,lp); - } - } - *lp = ntohl(*(int32_t *)(xdrs->x_private)); - xdrs->x_private += sizeof(int32_t); -#if DEBUG & DEBUG_VERB - fprintf(stderr,"Got aligned long %x\n",*lp); -#endif - return (TRUE); -} - -static bool_t -xdrmbuf_putlong_aligned(xdrs, lp) - register XDR *xdrs; - long *lp; -{ -fprintf(stderr,"TODO: xdrmbuf_putlong_aligned() is unimplemented\n"); - return FALSE; -#if 0 - if ((xdrs->x_handy -= sizeof(int32_t)) < 0) - return (FALSE); - *(int32_t *)xdrs->x_private = htonl(*lp); - xdrs->x_private += sizeof(int32_t); - return (TRUE); -#endif -} - -static bool_t -xdrmbuf_getlong_unaligned(xdrs, lp) - register XDR *xdrs; - long *lp; -{ -union { - int32_t l; - char c[sizeof(int32_t)]; -} u; - -register int i,j; -register char *cp,*sp; - - i = xdrs->x_handy - sizeof(int32_t); - - /* handle the most common case first */ - if ( i >= 0 ) { - - xdrs->x_handy = i; - sp = (char*)xdrs->x_private; - xdrs->x_private = sp + sizeof(int32_t); - -#ifdef CANDO_UNALIGNED - { - *lp = ntohl(*(int32_t *)sp); -# if DEBUG & DEBUG_VERB - fprintf(stderr,"Got unaligned long %x (%i remaining)\n",*lp, xdrs->x_handy); -# endif - return TRUE; - } -#else /* machine can't do unaligned access */ - { - u.c[0] = *sp; - u.c[1] = *++sp; - u.c[2] = *++sp; - u.c[3] = *++sp; - - goto done; - } -#endif /* CANDO_UNALIGNED */ - } - - /* here the messy 'crossing buffers' business starts */ - - - j = sizeof(int32_t); - - cp = u.c-1; - - /* NOTE: on entry to this section, handy < j holds */ - do { - sp = ((char*)xdrs->x_private)-1; - - if ( (i=xdrs->x_handy) >= j ) { - /* more data in the buffer than we need: - * copy everything we need and goto 'done' - */ - xdrs->x_handy = i-j; - do { - *++cp = *++sp; - } while (--j > 0); - xdrs->x_private = (caddr_t)++sp; - - goto done; - - } else { - /* not enough data - copy as much as possible - * then get retrieve the next MBUF and start - * over - */ - j-=i; - while (i--) - *++cp = *++sp; - if (!xdrmbuf_next(xdrs)) - return FALSE; -#if DEBUG & DEBUG_VERB - fprintf(stderr,"getlong_unaligned: crossed mbuf boundary\n"); -#endif - } - } while (j > 0); - -done: - - *lp = ntohl(u.l); - -#if DEBUG & DEBUG_VERB - fprintf(stderr,"Got unaligned long %x (%i remaining)\n",*lp, xdrs->x_handy); -#endif - return (TRUE); -} - -static bool_t -xdrmbuf_putlong_unaligned(xdrs, lp) - register XDR *xdrs; - long *lp; -{ - - fprintf(stderr,"TODO: xdrmbuf_putlong_unaligned() is unimplemented\n"); - return FALSE; -#if 0 - { - int32_t l; - - if ((xdrs->x_handy -= sizeof(int32_t)) < 0) - return (FALSE); - l = htonl(*lp); - memcpy(xdrs->x_private, &l, sizeof(int32_t)); - xdrs->x_private += sizeof(int32_t); - return (TRUE); - } -#endif -} - -static bool_t -xdrmbuf_getbytes(xdrs, addr, len) - register XDR *xdrs; - caddr_t addr; - register u_int len; -{ -#if DEBUG & DEBUG_VERB -int olen=len,bufs=0; -#endif - -#if DEBUG & DEBUG_VERB - fprintf(stderr,"wanting %i bytes (have %i)\n",olen,xdrs->x_handy); -#endif - - while (len>0) { - if (xdrs->x_handy >= len) { - memcpy(addr, xdrs->x_private, len); - xdrs->x_private += len; - xdrs->x_handy -= len; -#if 0 /* save a couple of instructions */ - len = 0; -#else - goto done; -#endif - } else { - if (xdrs->x_handy > 0) { - memcpy(addr, xdrs->x_private, xdrs->x_handy); - len -= xdrs->x_handy; - addr += xdrs->x_handy; - } - if (!xdrmbuf_next(xdrs)) - return FALSE; -#if DEBUG & DEBUG_VERB - bufs++; -#endif - } - } -done: -#if DEBUG & DEBUG_VERB - fprintf(stderr,"Got %i bytes (out of %i mbufs)\n",olen,bufs); -#endif - return (TRUE); -} - -static bool_t -xdrmbuf_putbytes(xdrs, addr, len) - register XDR *xdrs; - caddr_t addr; - register u_int len; -{ - - fprintf(stderr,"TODO: xdrmbuf_putbytes() is unimplemented\n"); - return FALSE; -#if 0 - if ((xdrs->x_handy -= len) < 0) - return (FALSE); - memcpy(xdrs->x_private, addr, len); - xdrs->x_private += len; - return (TRUE); -#endif -} - -static u_int -xdrmbuf_getpos(xdrs) - register XDR *xdrs; -{ -#if 1 -MBPrivate mbp = (MBPrivate)xdrs->x_base; -struct mbuf *m = mbp->mcurrent; -u_int rval = mbp->pos; - - if (m) { - rval += (u_long)xdrs->x_private - mtod(m, u_long); - } -#else -struct mbuf *m; -u_int rval = 0; -MBPrivate mbp = (MBPrivate)xdrs->x_base; - - for ( m = mbp->mchain; m && m != mbp->mcurrent; m = m->m_next ) - rval += m->m_len; - if (m) { - rval += (u_long)xdrs->x_private - mtod(m, u_long); - } - -#endif - return rval; -} - -static bool_t -xdrmbuf_setpos(xdrs, pos) - register XDR *xdrs; - u_int pos; -{ -struct mbuf *m; -MBPrivate mbp = (MBPrivate)xdrs->x_base; - - if (pos >= mbp->pos) { - pos -= mbp->pos; - m = mbp->mcurrent; - } else { - m = mbp->mchain; - mbp->pos = 0; - } - - while ( m && pos >= m->m_len ) { - pos -= m->m_len; - mbp->pos += m->m_len; - m = m->m_next; - } - - if (m) { - xdrmbuf_setup(xdrs, m); - xdrs->x_private += pos; - return TRUE; - } - - return 0 == pos ? TRUE : FALSE; -} - -static int32_t * -xdrmbuf_inline_aligned(xdrs, len) - register XDR *xdrs; - int len; -{ -int32_t *buf = 0; - - if (xdrs->x_handy == 0 && !xdrmbuf_next(xdrs)) - return 0; - - if (xdrs->x_handy >= len) { - xdrs->x_handy -= len; - buf = (int32_t *) xdrs->x_private; - xdrs->x_private += len; -#if DEBUG & DEBUG_VERB - fprintf(stderr,"Got %i aligned inline bytes at %x\n", len, buf); -#endif - } -#if DEBUG & DEBUG_VERB - else { - fprintf(stderr,"Skipped %i aligned inline bytes\n",len); - } -#endif - return (buf); -} - -static int32_t * -xdrmbuf_inline_unaligned(xdrs, len) - register XDR *xdrs; - int len; -{ - return (0); -} diff --git a/rtemsNfs/ChangeLog b/rtemsNfs/ChangeLog new file mode 100644 index 0000000..ab2a1f1 --- /dev/null +++ b/rtemsNfs/ChangeLog @@ -0,0 +1,37 @@ +Changes since RTEMS-NFS 1.1: + NFS: + - unlink() didnt work. The underlying RTEMS filesystem code evaluates + a '..' path on a non-directory node to find out the file's parent + directory. Workaround to this semantically inelegant RTEMS feature + was implemented. + +Changes since RTEMS-NFS 1.0.beta3: + NFS: + - fixed possible string overrun in nfsMount + - nfs_read_dir() must reset the 'eofreached' flag if it skipped + dirents present in the xdr but not fitting into the user buffer. + - nfsMountsShow() released the wrong lock! + RPCIO: + - cannot delete locked binary semaphore (authlock) -- must unlock + first (authlock was never deleted and hence effectively leaked) + - added ASSERT paranoia around mutex primitives + - Relaxed paranoia check / ASSERTion failure: + paranoia_free() is called more than once on an ext_buf - it must + undo calls to paranoia_refcnt() - hence the 0 == --refcnt check + is too strict. + - Added a DEBUG flag to introduce random packet losses for testing + retransmission. + xdr_mbuf: + - make sure we do a signed comparison + +Changes since rtemsNFS-1.0.beta2: + - moved 'tar' command to the 'config' area; use + predefined 'make-tar' in individual Makefiles + - use INSTALL_CHANGE for headers, not INSTALL_VARIANT (probably doesn't + matter, though) + - use LD not LD_FOR_TARGET (to get absolute path) + - fixed assertion failure print format + - print requestor id if send_event fails - had just experienced this :-( + - hint about fprintf using FP registers is probably PPC specific + - provided implementation for xdrmbuf_getlong_aligned(). i386-rtems + seems to use it. diff --git a/rtemsNfs/LICENSE b/rtemsNfs/LICENSE new file mode 100644 index 0000000..ba677ea --- /dev/null +++ b/rtemsNfs/LICENSE @@ -0,0 +1,115 @@ + + EPICS Open License Terms + + The following is the text of the EPICS Open software license agreement + which applies to many of the unbundled EPICS extensions and support + modules. + + -------------------------------------------------------------- + + Copyright © 2002, Stanford University and + Till Straumann + + RTEMS-NFS is distributed subject to the following license conditions: + + SOFTWARE LICENSE AGREEMENT + Software: RTEMS-NFS + + 1. The "Software", below, refers to RTEMS-NFS (in either source + code, or binary form and accompanying documentation). Each + licensee is addressed as "you" or "Licensee." + + RTEMS-NFS comprises all files under this directory with + the EXCEPTION OF + src/sock_mbuf.c + src/xdr_mbuf.c + proto/mount_prot.x + proto/nfs_prot.x + which are covered by the licenses described in the + LICENSE.NET and LICENSE.RPCXDR files (RTEMS source topdir) + and header comments in the mentioned files, respectively. + + 2. The copyright holders shown above and their third-party + licensors hereby grant Licensee a royalty-free nonexclusive + license, subject to the limitations stated herein and U.S. + Government license rights. + 3. You may modify and make a copy or copies of the Software for use + within your organization, if you meet the following conditions: + a. Copies in source code must include the copyright notice + and this Software License Agreement. + b. Copies in binary form must include the copyright notice + and this Software License Agreement in the documentation + and/or other materials provided with the copy. + + 4. You may modify a copy or copies of the Software or any portion + of it, thus forming a work based on the Software, and distribute + copies of such work outside your organization, if you meet all + of the following conditions: + a. Copies in source code must include the copyright notice + and this Software License Agreement; + b. Copies in binary form must include the copyright notice + and this Software License Agreement in the documentation + and/or other materials provided with the copy; + c. Modified copies and works based on the Software must carry + prominent notices stating that you changed specified + portions of the Software. + + 5. Portions of the Software resulted from work developed under a + U.S. Government contract and are subject to the following + license: the Government is granted for itself and others acting + on its behalf a paid-up, nonexclusive, irrevocable worldwide + license in this computer software to reproduce, prepare + derivative works, and perform publicly and display publicly. + 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT + WARRANTY OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY + LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF + ENERGY, AND THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY + OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS + OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE + WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT + THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS + ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. + 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, + THEIR THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED + STATES DEPARTMENT OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR + ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE + DAMAGES OF ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS + OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER + SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT + (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, EVEN + IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE POSSIBILITY OF + SUCH LOSS OR DAMAGES. + + Stanford Notice + *************** + + Acknowledgement of sponsorship + - - - - - - - - - - - - - - - - + This software was produced by the Stanford Linear Accelerator Center, + Stanford University, under Contract DE-AC03-76SFO0515 with the Department + of Energy. + + Government disclaimer of liability + - - - - - - - - - - - - - - - - - + Neither the United States nor the United States Department of Energy, + nor any of their employees, makes any warranty, express or implied, + or assumes any legal liability or responsibility for the accuracy, + completeness, or usefulness of any data, apparatus, product, or process + disclosed, or represents that its use would not infringe privately + owned rights. + + Stanford disclaimer of liability + - - - - - - - - - - - - - - - - - + Stanford University makes no representations or warranties, express or + implied, nor assumes any liability for the use of this software. + + Maintenance of notice + - - - - - - - - - - - + In the interest of clarity regarding the origin and status of this + software, Stanford University requests that any recipient of it maintain + this notice affixed to any distribution by the recipient that contains a + copy or derivative of this software. + diff --git a/rtemsNfs/Makefile b/rtemsNfs/Makefile new file mode 100644 index 0000000..a77b0f8 --- /dev/null +++ b/rtemsNfs/Makefile @@ -0,0 +1,16 @@ +# +# $Id$ +# + + +include $(RTEMS_MAKEFILE_PATH)/Makefile.inc + +include $(RTEMS_CUSTOM) +include $(RTEMS_ROOT)/make/directory.cfg + +SUBDIRS=proto src + +REVISION=$(filter-out $$%,$$Name$$) + +tar: tar-recursive + @$(make-tar) diff --git a/rtemsNfs/README b/rtemsNfs/README new file mode 100644 index 0000000..3291329 --- /dev/null +++ b/rtemsNfs/README @@ -0,0 +1,491 @@ +RTEMS-NFS +========= + +A NFS-V2 client implementation for the RTEMS real-time +executive. + +Author: Till Straumann , 2002 + +Copyright 2002, Stanford University and + Till Straumann + +Stanford Notice +*************** + +Acknowledgement of sponsorship +* * * * * * * * * * * * * * * * +This software was produced by the Stanford Linear Accelerator Center, +Stanford University, under Contract DE-AC03-76SFO0515 with the Department +of Energy. + + +Contents +-------- +I Overview + 1) Performance + 2) Reference Platform / Test Environment + +II Usage + 1) Initialization + 2) Mounting Remote Server Filesystems + 3) Unmounting + 4) Unloading + 5) Dumping Information / Statistics + +III Implementation Details + 1) RPCIOD + 2) NFS + 3) RTEMS Resources Used By NFS/RPCIOD + 4) Caveats & Bugs + +IV Licensing & Disclaimers + +I Overview +----------- + +This package implements a simple non-caching NFS client +for RTEMS. Most of the system calls are supported +with the exception of 'mount', i.e. it is not possible +to mount another FS on top of NFS (mostly because +of the difficulty that arises when mount points are +deleted on the server). It shouldn't be hard to do, +though. + +Note: this client supports NFS vers. 2 / MOUNT vers. 1; + NFS Version 3 or higher are NOT supported. + +The package consists of two modules: RPCIOD and NFS itself. + + - RPCIOD is a UDP/RPC multiplexor daemon. It takes + RPC requests from multiple local client threads, + funnels them through a single socket to multiple + servers and dispatches the replies back to the + (blocked) requestor threads. + RPCIOD does packet retransmission and handles + timeouts etc. + Note however, that it does NOT do any XDR + marshalling - it is up to the requestor threads + to do the XDR encoding/decoding. RPCIOD _is_ RPC + specific, though, because its message dispatching + is based on the RPC transaction ID. + + - The NFS package maps RTEMS filesystem calls + to proper RPCs, it does the XDR work and + hands marshalled RPC requests to RPCIOD. + All of the calls are synchronous, i.e. they + block until they get a reply. + +1) Performance +- - - - - - - - +Performance sucks (due to the lack of readahead/delayed +write and caching). On a fast (100Mb/s) ethernet, it +takes about 20s to copy a 10MB file from NFS to NFS. +I found, however, that vxWorks' NFS client doesn't seem +to be any faster... + +2) Reference Platform +- - - - - - - - - - - +RTEMS-NFS was developed and tested on + + o RTEMS-ss20020301 (local patches applied) + o PowerPC G3, G4 on Synergy SVGM series board + (custom 'SVGM' BSP, to be released soon) + o PowerPC 604 on MVME23xx + (powerpc/shared/motorola-powerpc BSP) + o Test Environment: + - RTEMS executable running CEXP + - rpciod/nfs dynamically loaded from TFTPfs + - EPICS application dynamically loaded from NFS; + the executing IOC accesses all of its files + on NFS. + +II Usage +--------- + +After linking into the system and proper initialization +(rtems-NFS supports 'magic' module initialization when +loaded into a running system with the CEXP loader), +you are ready for mounting NFSes from a server +(I avoid the term NFS filesystem because NFS already +stands for 'Network File System'). + +You should also read the + + - "RTEMS Resources Used By NFS/RPCIOD" + - "CAVEATS & BUGS" + +below. + +1) Initialization +- - - - - - - - - +NFS consists of two modules who must be initialized: + + a) the RPCIO daemon package; by calling + + rpcUdpInit(); + + note that this step must be performed prior to + initializing NFS: + + b) NFS is initialized by calling + + nfsInit( smallPoolDepth, bigPoolDepth ); + + if you supply 0 (zero) values for the pool + depths, the compile-time default configuration + is used which should work fine. + +NOTE: when using CEXP to load these modules into a +running system, initialization will be performed +automagically. + +2) Mounting Remote Server Filesystems +- - - - - - - - - - - - - - - - - - - + +There are two interfaces for mounting an NFS: + + - The (non-POSIX) RTEMS 'mount()' call: + + mount( &mount_table_entry_pointer, + &filesystem_operations_table_pointer, + options, + device, + mount_point ) + + Note that you must specify a 'mount_table_entry_pointer' + (use a dummy) - RTEMS' mount() doesn't grok a NULL for + the first argument. + + o for the 'filesystem_operations_table_pointer', supply + + &nfs_fs_ops + + o options are constants (see RTEMS headers) for specifying + read-only / read-write mounts. + + o the 'device' string specifies the remote filesystem + who is to be mounted. NFS expects a string conforming + to the following format (EBNF syntax): + + [ '.' '@' ] ':' + + The first optional part of the string allows you + to specify the credentials to be used for all + subsequent transactions with this server. If the + string is omitted, the EUID/EGID of the executing + thread (i.e. the thread performing the 'mount' - + NFS will still 'remember' these values and use them + for all future communication with this server). + + The part denotes the server IP address + in standard 'dot' notation. It is followed by + a colon and the (absolute) path on the server. + Note that no extra characters or whitespace must + be present in the string. Example 'device' strings + are: + + "300.99@192.168.44.3:/remote/rtems/root" + + "192.168.44.3:/remote/rtems/root" + + o the 'mount_point' string identifies the local + directory (most probably on IMFS) where the NFS + is to be mounted. Note that the mount point must + already exist with proper permissions. + + - Alternate 'mount' interface. NFS offers a more + convenient wrapper taking three string arguments: + + nfsMount(uidgid_at_host, server_path, mount_point) + + This interface does DNS lookup (see reentrancy note + below) and creates the mount point if necessary. + + o the first argument specifies the server and + optionally the uid/gid to be used for authentication. + The semantics are exactly as described above: + + [ '.' '@' ] + + The part may be either a host _name_ or + an IP address in 'dot' notation. In the former + case, nfsMount() uses 'gethostbyname()' to do + a DNS lookup. + + IMPORTANT NOTE: gethostbyname() is NOT reentrant/ + thread-safe and 'nfsMount()' (if not provided with an + IP/dot address string) is hence subject to race conditions. + + o the 'server_path' and 'mount_point' arguments + are described above. + NOTE: If the mount point does not exist yet, + nfsMount() tries to create it. + + o if nfsMount() is called with a NULL 'uidgid_at_host' + argument, it lists all currently mounted NFS + +3) Unmounting +- - - - - - - +An NFS can be unmounted using RTEMS 'unmount()' +call (yep, it is unmount() - not umount()): + + unmount(mount_point) + +Note that you _must_ supply the mount point (string +argument). It is _not_ possible to specify the +'mountee' when unmounting. NFS implements no +convenience wrapper for this (yet), essentially because +(although this sounds unbelievable) it is non-trivial +to lookup the path leading to an RTEMS filesystem +directory node. + +4) Unloading +- - - - - - - +After unmounting all NFS from the system, the NFS +and RPCIOD modules may be stopped and unloaded. +Just call 'nfsCleanup()' and 'rpcUdpCleanup()' +in this order. You should evaluate the return value +of these routines which is non-zero if either +of them refuses to yield (e.g. because there are +still mounted filesystems). +Again, when unloading is done by CEXP this is +transparently handled. + +5) Dumping Information / Statistics +- - - - - - - - - - - - - - - - - - + +Rudimentary RPCIOD statistics are printed +to a file (stdout when NULL) by + + int rpcUdpStats(FILE *f) + +A list of all currently mounted NFS can be +printed to a file (stdout if NULL) using + + int nfsMountsShow(FILE *f) + +For convenience, this routine is also called +by nfsMount() when supplying NULL arguments. + +III Implementation Details +-------------------------- + +1) RPCIOD +- - - - - + +RPCIOD was created to + +a) avoid non-reentrant librpc calls. +b) support 'asynchronous' operation over a single + socket. + +RPCIOD is a daemon thread handling 'transaction objects' +(XACTs) through an UDP socket. XACTs are marshalled RPC +calls/replies associated with RPC servers and requestor +threads. + +requestor thread: network: + + XACT packet + | | + V V + | message queue | ( socket ) + | | ^ + ----------> <----- | | + RPCIOD | + / -------------- + timeout/ (re) transmission + + +A requestor thread drops a transaction into +the message queue and goes to sleep. The XACT is +picked up by rpciod who is listening for events from +three sources: + + o the request queue + o packet arrival at the socket + o timeouts + +RPCIOD sends the XACT to its destination server and +enqueues the pending XACT into an ordered list of +outstanding transactions. + +When a packet arrives, RPCIOD (based on the RPC transaction +ID) looks up the matching XACT and wakes up the requestor +who can then XDR-decode the RPC results found in the XACT +object's buffer. + +When a timeout expires, RPCIOD examines the outstanding +XACT that is responsible for the timeout. If its lifetime +has not expired yet, RPCIOD resends the request. Otherwise, +the XACT's error status is set and the requestor is woken up. + +RPCIOD dynamically adjusts the retransmission intervals +based on the average round-trip time measured (on a per-server +basis). + +Having the requestors event driven (rather than blocking +e.g. on a semaphore) is geared to having many different +requestors (one synchronization object per requestor would +be needed otherwise). + +Requestors who want to do asynchronous IO need a different +interface which will be added in the future. + +1.a) Reentrancy +- - - - - - - - +RPCIOD does no non-reentrant librpc calls. + +1.b) Efficiency +- - - - - - - - +We shouldn't bother about efficiency until pipelining (read-ahead/ +delayed write) and caching are implemented. The round-trip delay +associated with every single RPC transaction clearly is a big +performance killer. + +Nevertheless, I could not withstand the temptation to eliminate +the extra copy step involved with socket IO: + +A user data object has to be XDR encoded into a buffer. The +buffer given to the socket where it is copied into MBUFs. +(The network chip driver might even do more copying). + +Likewise, on reception 'recvfrom' copies MBUFS into a user +buffer which is XDR decoded into the final user data object. + +Eliminating the copying into (possibly multiple) MBUFS by +'sendto()' is actually a piece of cake. RPCIOD uses the +'sosend()' routine [properly wrapped] supplying a single +MBUF header who directly points to the marshalled buffer +:-) + +Getting rid of the extra copy on reception was (only a little) +harder: I derived a 'XDR-mbuf' stream from SUN's xdr_mem which +allows for XDR-decoding out of a MBUF chain who is obtained by +soreceive(). + +2) NFS +- - - - +The actual NFS implementation is straightforward and essentially +'passive' (no threads created). Any RTEMS task executing a +filesystem call dispatched to NFS (such as 'opendir()', 'lseek()' +or 'unlink()') ends up XDR encoding arguments, dropping a +XACT into RPCIOD's message queue and going to sleep. +When woken up by RPCIOD, the XACT is decoded (using the XDR-mbuf +stream mentioned above) and the properly cooked-up results are +returned. + +3) RTEMS Resources Used By NFS/RPCIOD +- - - - - - - - - - - - - - - - - - - + +The RPCIOD/NFS package uses the following resources. Some +parameters are compile-time configurable - consult the +source files for details. + +RPCIOD: + o 1 task + o 1 message queue + o 1 socket/filedescriptor + o 2 semaphores (a third one is temporarily created during + rpcUdpCleanup()). + o 1 RTEMS EVENT (by default RTEMS_EVENT_30). + IMPORTANT: this event is used by _every_ thread executing + NFS system calls and hence is RESERVED. + o 3 events only used by RPCIOD itself, i.e. these must not + be sent to RPCIOD by no other thread (except for the intended + use, of course). The events involved are 1,2,3. + o preemption disabled sections: NONE + o sections with interrupts disabled: NONE + o NO 'timers' are used (timer code would run in IRQ context) + o memory usage: n.a + +NFS: + o 2 message queues + o 2 semaphores + o 1 semaphore per mounted NFS + o 1 slot in driver entry table (for major number) + o preemption disabled sections: NONE + o sections with interrupts disabled: NONE + o 1 task + 1 semaphore temporarily created when + listing mounted filesystems (rtems_filesystem_resolve_location()) + +4) CAVEATS & BUGS +- - - - - - - - - +Unfortunately, some bugs crawl around in the filesystem generics. +(Some of them might already be fixed in versions later than +rtems-ss-20020301). +I recommend to use the patch distributed with RTEMS-NFS. + + o RTEMS uses/used (Joel said it has been fixed already) a 'short' + ino_t which is not enough for NFS. + The driver detects this problem and enables a workaround. In rare + situations (mainly involving 'getcwd()' improper inode comparison + may result (due to the restricted size, stat() returns st_ino modulo + 2^16). In most cases, however, st_dev is compared along with st_ino + which will give correct results (different files may yield identical + st_ino but they will have different st_dev). However, there is + code (in getcwd(), for example) who assumes that files residing + in one directory must be hosted by the same device and hence omits + the st_dev comparison. In such a case, the workaround will fail. + + NOTE: changing the size (sys/types.h) of ino_t from 'short' to 'long' + is strongly recommended. It is NOT included in the patch, however + as this is a major change requiring ALL of your sources to + be recompiled. + + THE ino_t SIZE IS FIXED IN GCC-3.2/NEWLIB-1.10.0-2 DISTRIBUTED BY + OAR. + + o You may work around most filesystem bugs by observing the following + rules: + + * never use chroot() (fixed by the patch) + * never use getpwent(), getgrent() & friends - they are NOT THREAD + safe (fixed by the patch) + * NEVER use rtems_libio_share_private_env() - not even with the + patch applied. Just DONT - it is broken by design. + * All threads who have their own userenv (who have called + rtems_libio_set_private_env()) SHOULD 'chdir("/")' before + terminating. Otherwise, (i.e. if their cwd is on NFS), it will + be impossible to unmount the NFS involved. + + o The patch slightly changes the semantics of 'getpwent()' and + 'getgrent()' & friends (to what is IMHO correct anyways - the patch is + also needed to fix another problem, however): with the patch applied, + the passwd and group files are always accessed from the 'current' user + environment, i.e. a thread who has changed its 'root' or 'uid' might + not be able to access these files anymore. + + o NOTE: RTEMS 'mount()' / 'unmount()' are NOT THREAD SAFE. + +IV Licensing & Disclaimers +-------------------------- + +NFS is distributed under the EPICS Open License - consult the +separate 'LICENSE' file. + +Government disclaimer of liability +- - - - - - - - - - - - - - - - - +Neither the United States nor the United States Department of Energy, +nor any of their employees, makes any warranty, express or implied, +or assumes any legal liability or responsibility for the accuracy, +completeness, or usefulness of any data, apparatus, product, or process +disclosed, or represents that its use would not infringe privately +owned rights. + +Stanford disclaimer of liability +- - - - - - - - - - - - - - - - - +Stanford University makes no representations or warranties, express or +implied, nor assumes any liability for the use of this software. + +This product is subject to the EPICS open license +- - - - - - - - - - - - - - - - - - - - - - - - - +Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php +for more information. + +Maintenance of notice +- - - - - - - - - - - +In the interest of clarity regarding the origin and status of this +software, Stanford University requests that any recipient of it maintain +this notice affixed to any distribution by the recipient that contains a +copy or derivative of this software. diff --git a/rtemsNfs/proto/Makefile b/rtemsNfs/proto/Makefile new file mode 100644 index 0000000..57a9830 --- /dev/null +++ b/rtemsNfs/proto/Makefile @@ -0,0 +1,75 @@ +# +# $Id$ +# +# Templates/Makefile.lib +# Template library Makefile +# + + +LIBNAME=libnfsprot.a # xxx- your library names goes here +LIB=${ARCH}/${LIBNAME} + +# C and C++ source names, if any, go here -- minus the .c or .cc +C_PIECES=nfs_prot_xdr mount_prot_xdr +C_FILES=$(C_PIECES:%=%.c) +C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) + +CC_PIECES= +CC_FILES=$(CC_PIECES:%=%.cc) +CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o) + +H_FILES= + +XFILES = $(wildcard *.x) + +# Assembly source names, if any, go here -- minus the .S +S_PIECES= +S_FILES=$(S_PIECES:%=%.S) +S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o) + +SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) +OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES) + +include $(RTEMS_MAKEFILE_PATH)/Makefile.inc + +include $(RTEMS_CUSTOM) +include $(RTEMS_ROOT)/make/lib.cfg + +# +# Add local stuff here using += +# + +DEFINES += +CPPFLAGS += +# inline declarations require -O +CFLAGS += -O2 -Winline + +# +# Add your list of files to delete here. The config files +# already know how to delete some stuff, so you may want +# to just run 'make clean' first to see what gets missed. +# 'make clobber' already includes 'make clean' +# + +CLEAN_ADDITIONS += +CLOBBER_ADDITIONS += $(XFILES:%.x=%*.c) $(XFILES:%.x=%*.h) + +all: ${ARCH} $(SRCS) $(LIB) + +$(LIB): ${OBJS} + $(make-library) + +%_xdr.c: %.x %.h + rpcgen -c $< > $@ + +%.h: %.x + rpcgen -h $< > $@ + +.PRECIOUS: $(XFILES:%.x=%.h) $(XFILES:%.x=%_xdr.c) + +tar: $(XFILES:%.x=%.h) $(XFILES:%.x=%_xdr.c) + +distclean: clean + +# DONT install this library. +install: all diff --git a/rtemsNfs/proto/mount_prot.h b/rtemsNfs/proto/mount_prot.h new file mode 100644 index 0000000..1cde517 --- /dev/null +++ b/rtemsNfs/proto/mount_prot.h @@ -0,0 +1,144 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _MOUNT_PROT_H_RPCGEN +#define _MOUNT_PROT_H_RPCGEN + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 +#define FHSIZE 32 + +typedef char fhandle[FHSIZE]; + +struct fhstatus { + u_int fhs_status; + union { + fhandle fhs_fhandle; + } fhstatus_u; +}; +typedef struct fhstatus fhstatus; + +typedef char *dirpath; + +typedef char *name; + +typedef struct mountbody *mountlist; + +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; +typedef struct mountbody mountbody; + +typedef struct groupnode *groups; + +struct groupnode { + name gr_name; + groups gr_next; +}; +typedef struct groupnode groupnode; + +typedef struct exportnode *exports; + +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; +typedef struct exportnode exportnode; + +#define MOUNTPROG 100005 +#define MOUNTVERS 1 + +#if defined(__STDC__) || defined(__cplusplus) +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_1(void *, CLIENT *); +extern void * mountproc_null_1_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT 1 +extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_1(void *, CLIENT *); +extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_1(dirpath *, CLIENT *); +extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_1(void *, CLIENT *); +extern void * mountproc_umntall_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_1(void *, CLIENT *); +extern exports * mountproc_export_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORTALL 6 +extern exports * mountproc_exportall_1(void *, CLIENT *); +extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); +extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_1(); +extern void * mountproc_null_1_svc(); +#define MOUNTPROC_MNT 1 +extern fhstatus * mountproc_mnt_1(); +extern fhstatus * mountproc_mnt_1_svc(); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_1(); +extern mountlist * mountproc_dump_1_svc(); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_1(); +extern void * mountproc_umnt_1_svc(); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_1(); +extern void * mountproc_umntall_1_svc(); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_1(); +extern exports * mountproc_export_1_svc(); +#define MOUNTPROC_EXPORTALL 6 +extern exports * mountproc_exportall_1(); +extern exports * mountproc_exportall_1_svc(); +extern int mountprog_1_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_fhandle (XDR *, fhandle); +extern bool_t xdr_fhstatus (XDR *, fhstatus*); +extern bool_t xdr_dirpath (XDR *, dirpath*); +extern bool_t xdr_name (XDR *, name*); +extern bool_t xdr_mountlist (XDR *, mountlist*); +extern bool_t xdr_mountbody (XDR *, mountbody*); +extern bool_t xdr_groups (XDR *, groups*); +extern bool_t xdr_groupnode (XDR *, groupnode*); +extern bool_t xdr_exports (XDR *, exports*); +extern bool_t xdr_exportnode (XDR *, exportnode*); + +#else /* K&R C */ +extern bool_t xdr_fhandle (); +extern bool_t xdr_fhstatus (); +extern bool_t xdr_dirpath (); +extern bool_t xdr_name (); +extern bool_t xdr_mountlist (); +extern bool_t xdr_mountbody (); +extern bool_t xdr_groups (); +extern bool_t xdr_groupnode (); +extern bool_t xdr_exports (); +extern bool_t xdr_exportnode (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_MOUNT_PROT_H_RPCGEN */ diff --git a/rtemsNfs/proto/mount_prot.x b/rtemsNfs/proto/mount_prot.x new file mode 100644 index 0000000..444e998 --- /dev/null +++ b/rtemsNfs/proto/mount_prot.x @@ -0,0 +1,161 @@ +/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */ +/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Protocol description for the mount program + */ + + +const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ +const MNTNAMLEN = 255; /* maximum bytes in a name argument */ +const FHSIZE = 32; /* size in bytes of a file handle */ + +/* + * The fhandle is the file handle that the server passes to the client. + * All file operations are done using the file handles to refer to a file + * or a directory. The file handle can contain whatever information the + * server needs to distinguish an individual file. + */ +typedef opaque fhandle[FHSIZE]; + +/* + * If a status of zero is returned, the call completed successfully, and + * a file handle for the directory follows. A non-zero status indicates + * some sort of error. The status corresponds with UNIX error numbers. + */ +union fhstatus switch (unsigned fhs_status) { +case 0: + fhandle fhs_fhandle; +default: + void; +}; + +/* + * The type dirpath is the pathname of a directory + */ +typedef string dirpath; + +/* + * The type name is used for arbitrary names (hostnames, groupnames) + */ +typedef string name; + +/* + * A list of who has what mounted + */ +typedef struct mountbody *mountlist; +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; + +/* + * A list of netgroups + */ +typedef struct groupnode *groups; +struct groupnode { + name gr_name; + groups gr_next; +}; + +/* + * A list of what is exported and to whom + */ +typedef struct exportnode *exports; +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; + +program MOUNTPROG { + /* + * Version one of the mount protocol communicates with version two + * of the NFS protocol. The only connecting point is the fhandle + * structure, which is the same for both protocols. + */ + version MOUNTVERS { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + } = 1; +} = 100005; diff --git a/rtemsNfs/proto/mount_prot_xdr.c b/rtemsNfs/proto/mount_prot_xdr.c new file mode 100644 index 0000000..b83350b --- /dev/null +++ b/rtemsNfs/proto/mount_prot_xdr.c @@ -0,0 +1,124 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "mount_prot.h" + +bool_t +xdr_fhandle (XDR *xdrs, fhandle objp) +{ + register int32_t *buf; + + if (!xdr_opaque (xdrs, objp, FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhstatus (XDR *xdrs, fhstatus *objp) +{ + register int32_t *buf; + + if (!xdr_u_int (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_dirpath (XDR *xdrs, dirpath *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_name (XDR *xdrs, name *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, objp, MNTNAMLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountlist (XDR *xdrs, mountlist *objp) +{ + register int32_t *buf; + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct mountbody), (xdrproc_t) xdr_mountbody)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountbody (XDR *xdrs, mountbody *objp) +{ + register int32_t *buf; + + if (!xdr_name (xdrs, &objp->ml_hostname)) + return FALSE; + if (!xdr_dirpath (xdrs, &objp->ml_directory)) + return FALSE; + if (!xdr_mountlist (xdrs, &objp->ml_next)) + return FALSE; + return TRUE; +} + +bool_t +xdr_groups (XDR *xdrs, groups *objp) +{ + register int32_t *buf; + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct groupnode), (xdrproc_t) xdr_groupnode)) + return FALSE; + return TRUE; +} + +bool_t +xdr_groupnode (XDR *xdrs, groupnode *objp) +{ + register int32_t *buf; + + if (!xdr_name (xdrs, &objp->gr_name)) + return FALSE; + if (!xdr_groups (xdrs, &objp->gr_next)) + return FALSE; + return TRUE; +} + +bool_t +xdr_exports (XDR *xdrs, exports *objp) +{ + register int32_t *buf; + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct exportnode), (xdrproc_t) xdr_exportnode)) + return FALSE; + return TRUE; +} + +bool_t +xdr_exportnode (XDR *xdrs, exportnode *objp) +{ + register int32_t *buf; + + if (!xdr_dirpath (xdrs, &objp->ex_dir)) + return FALSE; + if (!xdr_groups (xdrs, &objp->ex_groups)) + return FALSE; + if (!xdr_exports (xdrs, &objp->ex_next)) + return FALSE; + return TRUE; +} diff --git a/rtemsNfs/proto/nfs_prot.h b/rtemsNfs/proto/nfs_prot.h new file mode 100644 index 0000000..de812db --- /dev/null +++ b/rtemsNfs/proto/nfs_prot.h @@ -0,0 +1,453 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _NFS_PROT_H_RPCGEN +#define _NFS_PROT_H_RPCGEN + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFS_PORT 2049 +#define NFS_MAXDATA 8192 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_FHSIZE 32 +#define NFS_COOKIESIZE 4 +#define NFS_FIFO_DEV -1 +#define NFSMODE_FMT 0170000 +#define NFSMODE_DIR 0040000 +#define NFSMODE_CHR 0020000 +#define NFSMODE_BLK 0060000 +#define NFSMODE_REG 0100000 +#define NFSMODE_LNK 0120000 +#define NFSMODE_SOCK 0140000 +#define NFSMODE_FIFO 0010000 + +enum nfsstat { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_WFLUSH = 99, +}; +typedef enum nfsstat nfsstat; + +enum ftype { + NFNON = 0, + NFREG = 1, + NFDIR = 2, + NFBLK = 3, + NFCHR = 4, + NFLNK = 5, + NFSOCK = 6, + NFBAD = 7, + NFFIFO = 8, +}; +typedef enum ftype ftype; + +struct nfs_fh { + char data[NFS_FHSIZE]; +}; +typedef struct nfs_fh nfs_fh; + +struct nfstime { + u_int seconds; + u_int useconds; +}; +typedef struct nfstime nfstime; + +struct fattr { + ftype type; + u_int mode; + u_int nlink; + u_int uid; + u_int gid; + u_int size; + u_int blocksize; + u_int rdev; + u_int blocks; + u_int fsid; + u_int fileid; + nfstime atime; + nfstime mtime; + nfstime ctime; +}; +typedef struct fattr fattr; + +struct sattr { + u_int mode; + u_int uid; + u_int gid; + u_int size; + nfstime atime; + nfstime mtime; +}; +typedef struct sattr sattr; + +typedef char *filename; + +typedef char *nfspath; + +struct attrstat { + nfsstat status; + union { + fattr attributes; + } attrstat_u; +}; +typedef struct attrstat attrstat; + +struct sattrargs { + nfs_fh file; + sattr attributes; +}; +typedef struct sattrargs sattrargs; + +struct diropargs { + nfs_fh dir; + filename name; +}; +typedef struct diropargs diropargs; + +struct diropokres { + nfs_fh file; + fattr attributes; +}; +typedef struct diropokres diropokres; + +struct diropres { + nfsstat status; + union { + diropokres diropres; + } diropres_u; +}; +typedef struct diropres diropres; + +struct readlinkres { + nfsstat status; + union { + nfspath data; + } readlinkres_u; +}; +typedef struct readlinkres readlinkres; + +struct readargs { + nfs_fh file; + u_int offset; + u_int count; + u_int totalcount; +}; +typedef struct readargs readargs; + +struct readokres { + fattr attributes; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct readokres readokres; + +struct readres { + nfsstat status; + union { + readokres reply; + } readres_u; +}; +typedef struct readres readres; + +struct writeargs { + nfs_fh file; + u_int beginoffset; + u_int offset; + u_int totalcount; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct writeargs writeargs; + +struct createargs { + diropargs where; + sattr attributes; +}; +typedef struct createargs createargs; + +struct renameargs { + diropargs from; + diropargs to; +}; +typedef struct renameargs renameargs; + +struct linkargs { + nfs_fh from; + diropargs to; +}; +typedef struct linkargs linkargs; + +struct symlinkargs { + diropargs from; + nfspath to; + sattr attributes; +}; +typedef struct symlinkargs symlinkargs; + +struct nfscookie { + char data[NFS_COOKIESIZE]; +}; +typedef struct nfscookie nfscookie; + +struct readdirargs { + nfs_fh dir; + nfscookie cookie; + u_int count; +}; +typedef struct readdirargs readdirargs; + +struct entry { + u_int fileid; + filename name; + nfscookie cookie; + struct entry *nextentry; +}; +typedef struct entry entry; + +struct dirlist { + entry *entries; + bool_t eof; +}; +typedef struct dirlist dirlist; + +struct readdirres { + nfsstat status; + union { + dirlist reply; + } readdirres_u; +}; +typedef struct readdirres readdirres; + +struct statfsokres { + u_int tsize; + u_int bsize; + u_int blocks; + u_int bfree; + u_int bavail; +}; +typedef struct statfsokres statfsokres; + +struct statfsres { + nfsstat status; + union { + statfsokres reply; + } statfsres_u; +}; +typedef struct statfsres statfsres; + +#define NFS_PROGRAM 100003 +#define NFS_VERSION 2 + +#if defined(__STDC__) || defined(__cplusplus) +#define NFSPROC_NULL 0 +extern void * nfsproc_null_2(void *, CLIENT *); +extern void * nfsproc_null_2_svc(void *, struct svc_req *); +#define NFSPROC_GETATTR 1 +extern attrstat * nfsproc_getattr_2(nfs_fh *, CLIENT *); +extern attrstat * nfsproc_getattr_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_SETATTR 2 +extern attrstat * nfsproc_setattr_2(sattrargs *, CLIENT *); +extern attrstat * nfsproc_setattr_2_svc(sattrargs *, struct svc_req *); +#define NFSPROC_ROOT 3 +extern void * nfsproc_root_2(void *, CLIENT *); +extern void * nfsproc_root_2_svc(void *, struct svc_req *); +#define NFSPROC_LOOKUP 4 +extern diropres * nfsproc_lookup_2(diropargs *, CLIENT *); +extern diropres * nfsproc_lookup_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READLINK 5 +extern readlinkres * nfsproc_readlink_2(nfs_fh *, CLIENT *); +extern readlinkres * nfsproc_readlink_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_READ 6 +extern readres * nfsproc_read_2(readargs *, CLIENT *); +extern readres * nfsproc_read_2_svc(readargs *, struct svc_req *); +#define NFSPROC_WRITECACHE 7 +extern void * nfsproc_writecache_2(void *, CLIENT *); +extern void * nfsproc_writecache_2_svc(void *, struct svc_req *); +#define NFSPROC_WRITE 8 +extern attrstat * nfsproc_write_2(writeargs *, CLIENT *); +extern attrstat * nfsproc_write_2_svc(writeargs *, struct svc_req *); +#define NFSPROC_CREATE 9 +extern diropres * nfsproc_create_2(createargs *, CLIENT *); +extern diropres * nfsproc_create_2_svc(createargs *, struct svc_req *); +#define NFSPROC_REMOVE 10 +extern nfsstat * nfsproc_remove_2(diropargs *, CLIENT *); +extern nfsstat * nfsproc_remove_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_RENAME 11 +extern nfsstat * nfsproc_rename_2(renameargs *, CLIENT *); +extern nfsstat * nfsproc_rename_2_svc(renameargs *, struct svc_req *); +#define NFSPROC_LINK 12 +extern nfsstat * nfsproc_link_2(linkargs *, CLIENT *); +extern nfsstat * nfsproc_link_2_svc(linkargs *, struct svc_req *); +#define NFSPROC_SYMLINK 13 +extern nfsstat * nfsproc_symlink_2(symlinkargs *, CLIENT *); +extern nfsstat * nfsproc_symlink_2_svc(symlinkargs *, struct svc_req *); +#define NFSPROC_MKDIR 14 +extern diropres * nfsproc_mkdir_2(createargs *, CLIENT *); +extern diropres * nfsproc_mkdir_2_svc(createargs *, struct svc_req *); +#define NFSPROC_RMDIR 15 +extern nfsstat * nfsproc_rmdir_2(diropargs *, CLIENT *); +extern nfsstat * nfsproc_rmdir_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READDIR 16 +extern readdirres * nfsproc_readdir_2(readdirargs *, CLIENT *); +extern readdirres * nfsproc_readdir_2_svc(readdirargs *, struct svc_req *); +#define NFSPROC_STATFS 17 +extern statfsres * nfsproc_statfs_2(nfs_fh *, CLIENT *); +extern statfsres * nfsproc_statfs_2_svc(nfs_fh *, struct svc_req *); +extern int nfs_program_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define NFSPROC_NULL 0 +extern void * nfsproc_null_2(); +extern void * nfsproc_null_2_svc(); +#define NFSPROC_GETATTR 1 +extern attrstat * nfsproc_getattr_2(); +extern attrstat * nfsproc_getattr_2_svc(); +#define NFSPROC_SETATTR 2 +extern attrstat * nfsproc_setattr_2(); +extern attrstat * nfsproc_setattr_2_svc(); +#define NFSPROC_ROOT 3 +extern void * nfsproc_root_2(); +extern void * nfsproc_root_2_svc(); +#define NFSPROC_LOOKUP 4 +extern diropres * nfsproc_lookup_2(); +extern diropres * nfsproc_lookup_2_svc(); +#define NFSPROC_READLINK 5 +extern readlinkres * nfsproc_readlink_2(); +extern readlinkres * nfsproc_readlink_2_svc(); +#define NFSPROC_READ 6 +extern readres * nfsproc_read_2(); +extern readres * nfsproc_read_2_svc(); +#define NFSPROC_WRITECACHE 7 +extern void * nfsproc_writecache_2(); +extern void * nfsproc_writecache_2_svc(); +#define NFSPROC_WRITE 8 +extern attrstat * nfsproc_write_2(); +extern attrstat * nfsproc_write_2_svc(); +#define NFSPROC_CREATE 9 +extern diropres * nfsproc_create_2(); +extern diropres * nfsproc_create_2_svc(); +#define NFSPROC_REMOVE 10 +extern nfsstat * nfsproc_remove_2(); +extern nfsstat * nfsproc_remove_2_svc(); +#define NFSPROC_RENAME 11 +extern nfsstat * nfsproc_rename_2(); +extern nfsstat * nfsproc_rename_2_svc(); +#define NFSPROC_LINK 12 +extern nfsstat * nfsproc_link_2(); +extern nfsstat * nfsproc_link_2_svc(); +#define NFSPROC_SYMLINK 13 +extern nfsstat * nfsproc_symlink_2(); +extern nfsstat * nfsproc_symlink_2_svc(); +#define NFSPROC_MKDIR 14 +extern diropres * nfsproc_mkdir_2(); +extern diropres * nfsproc_mkdir_2_svc(); +#define NFSPROC_RMDIR 15 +extern nfsstat * nfsproc_rmdir_2(); +extern nfsstat * nfsproc_rmdir_2_svc(); +#define NFSPROC_READDIR 16 +extern readdirres * nfsproc_readdir_2(); +extern readdirres * nfsproc_readdir_2_svc(); +#define NFSPROC_STATFS 17 +extern statfsres * nfsproc_statfs_2(); +extern statfsres * nfsproc_statfs_2_svc(); +extern int nfs_program_2_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_nfsstat (XDR *, nfsstat*); +extern bool_t xdr_ftype (XDR *, ftype*); +extern bool_t xdr_nfs_fh (XDR *, nfs_fh*); +extern bool_t xdr_nfstime (XDR *, nfstime*); +extern bool_t xdr_fattr (XDR *, fattr*); +extern bool_t xdr_sattr (XDR *, sattr*); +extern bool_t xdr_filename (XDR *, filename*); +extern bool_t xdr_nfspath (XDR *, nfspath*); +extern bool_t xdr_attrstat (XDR *, attrstat*); +extern bool_t xdr_sattrargs (XDR *, sattrargs*); +extern bool_t xdr_diropargs (XDR *, diropargs*); +extern bool_t xdr_diropokres (XDR *, diropokres*); +extern bool_t xdr_diropres (XDR *, diropres*); +extern bool_t xdr_readlinkres (XDR *, readlinkres*); +extern bool_t xdr_readargs (XDR *, readargs*); +extern bool_t xdr_readokres (XDR *, readokres*); +extern bool_t xdr_readres (XDR *, readres*); +extern bool_t xdr_writeargs (XDR *, writeargs*); +extern bool_t xdr_createargs (XDR *, createargs*); +extern bool_t xdr_renameargs (XDR *, renameargs*); +extern bool_t xdr_linkargs (XDR *, linkargs*); +extern bool_t xdr_symlinkargs (XDR *, symlinkargs*); +extern bool_t xdr_nfscookie (XDR *, nfscookie*); +extern bool_t xdr_readdirargs (XDR *, readdirargs*); +extern bool_t xdr_entry (XDR *, entry*); +extern bool_t xdr_dirlist (XDR *, dirlist*); +extern bool_t xdr_readdirres (XDR *, readdirres*); +extern bool_t xdr_statfsokres (XDR *, statfsokres*); +extern bool_t xdr_statfsres (XDR *, statfsres*); + +#else /* K&R C */ +extern bool_t xdr_nfsstat (); +extern bool_t xdr_ftype (); +extern bool_t xdr_nfs_fh (); +extern bool_t xdr_nfstime (); +extern bool_t xdr_fattr (); +extern bool_t xdr_sattr (); +extern bool_t xdr_filename (); +extern bool_t xdr_nfspath (); +extern bool_t xdr_attrstat (); +extern bool_t xdr_sattrargs (); +extern bool_t xdr_diropargs (); +extern bool_t xdr_diropokres (); +extern bool_t xdr_diropres (); +extern bool_t xdr_readlinkres (); +extern bool_t xdr_readargs (); +extern bool_t xdr_readokres (); +extern bool_t xdr_readres (); +extern bool_t xdr_writeargs (); +extern bool_t xdr_createargs (); +extern bool_t xdr_renameargs (); +extern bool_t xdr_linkargs (); +extern bool_t xdr_symlinkargs (); +extern bool_t xdr_nfscookie (); +extern bool_t xdr_readdirargs (); +extern bool_t xdr_entry (); +extern bool_t xdr_dirlist (); +extern bool_t xdr_readdirres (); +extern bool_t xdr_statfsokres (); +extern bool_t xdr_statfsres (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_NFS_PROT_H_RPCGEN */ diff --git a/rtemsNfs/proto/nfs_prot.x b/rtemsNfs/proto/nfs_prot.x new file mode 100644 index 0000000..a40d9a5 --- /dev/null +++ b/rtemsNfs/proto/nfs_prot.x @@ -0,0 +1,1268 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#ifndef RPC_HDR +%#ifndef lint +%/*static char sccsid[] = "from: @(#)nfs_prot.x 1.2 87/10/12 Copyr 1987 Sun Micro";*/ +%/*static char sccsid[] = "from: @(#)nfs_prot.x 2.1 88/08/01 4.0 RPCSRC";*/ +%static char rcsid[] = "$Id$"; +%#endif /* not lint */ +#endif + +const NFS_PORT = 2049; +const NFS_MAXDATA = 8192; +const NFS_MAXPATHLEN = 1024; +const NFS_MAXNAMLEN = 255; +const NFS_FHSIZE = 32; +const NFS_COOKIESIZE = 4; +const NFS_FIFO_DEV = -1; /* size kludge for named pipes */ + +/* + * File types + */ +const NFSMODE_FMT = 0170000; /* type of file */ +const NFSMODE_DIR = 0040000; /* directory */ +const NFSMODE_CHR = 0020000; /* character special */ +const NFSMODE_BLK = 0060000; /* block special */ +const NFSMODE_REG = 0100000; /* regular */ +const NFSMODE_LNK = 0120000; /* symbolic link */ +const NFSMODE_SOCK = 0140000; /* socket */ +const NFSMODE_FIFO = 0010000; /* fifo */ + +/* + * Error status + */ +enum nfsstat { + NFS_OK= 0, /* no error */ + NFSERR_PERM=1, /* Not owner */ + NFSERR_NOENT=2, /* No such file or directory */ + NFSERR_IO=5, /* I/O error */ + NFSERR_NXIO=6, /* No such device or address */ + NFSERR_ACCES=13, /* Permission denied */ + NFSERR_EXIST=17, /* File exists */ + NFSERR_NODEV=19, /* No such device */ + NFSERR_NOTDIR=20, /* Not a directory*/ + NFSERR_ISDIR=21, /* Is a directory */ + NFSERR_FBIG=27, /* File too large */ + NFSERR_NOSPC=28, /* No space left on device */ + NFSERR_ROFS=30, /* Read-only file system */ + NFSERR_NAMETOOLONG=63, /* File name too long */ + NFSERR_NOTEMPTY=66, /* Directory not empty */ + NFSERR_DQUOT=69, /* Disc quota exceeded */ + NFSERR_STALE=70, /* Stale NFS file handle */ + NFSERR_WFLUSH=99 /* write cache flushed */ +}; + +/* + * File types + */ +enum ftype { + NFNON = 0, /* non-file */ + NFREG = 1, /* regular file */ + NFDIR = 2, /* directory */ + NFBLK = 3, /* block special */ + NFCHR = 4, /* character special */ + NFLNK = 5, /* symbolic link */ + NFSOCK = 6, /* unix domain sockets */ + NFBAD = 7, /* unused */ + NFFIFO = 8 /* named pipe */ +}; + +/* + * File access handle + */ +struct nfs_fh { + opaque data[NFS_FHSIZE]; +}; + +/* + * Timeval + */ +struct nfstime { + unsigned seconds; + unsigned useconds; +}; + + +/* + * File attributes + */ +struct fattr { + ftype type; /* file type */ + unsigned mode; /* protection mode bits */ + unsigned nlink; /* # hard links */ + unsigned uid; /* owner user id */ + unsigned gid; /* owner group id */ + unsigned size; /* file size in bytes */ + unsigned blocksize; /* prefered block size */ + unsigned rdev; /* special device # */ + unsigned blocks; /* Kb of disk used by file */ + unsigned fsid; /* device # */ + unsigned fileid; /* inode # */ + nfstime atime; /* time of last access */ + nfstime mtime; /* time of last modification */ + nfstime ctime; /* time of last change */ +}; + +/* + * File attributes which can be set + */ +struct sattr { + unsigned mode; /* protection mode bits */ + unsigned uid; /* owner user id */ + unsigned gid; /* owner group id */ + unsigned size; /* file size in bytes */ + nfstime atime; /* time of last access */ + nfstime mtime; /* time of last modification */ +}; + + +typedef string filename; +typedef string nfspath; + +/* + * Reply status with file attributes + */ +union attrstat switch (nfsstat status) { +case NFS_OK: + fattr attributes; +default: + void; +}; + +struct sattrargs { + nfs_fh file; + sattr attributes; +}; + +/* + * Arguments for directory operations + */ +struct diropargs { + nfs_fh dir; /* directory file handle */ + filename name; /* name (up to NFS_MAXNAMLEN bytes) */ +}; + +struct diropokres { + nfs_fh file; + fattr attributes; +}; + +/* + * Results from directory operation + */ +union diropres switch (nfsstat status) { +case NFS_OK: + diropokres diropres; +default: + void; +}; + +union readlinkres switch (nfsstat status) { +case NFS_OK: + nfspath data; +default: + void; +}; + +/* + * Arguments to remote read + */ +struct readargs { + nfs_fh file; /* handle for file */ + unsigned offset; /* byte offset in file */ + unsigned count; /* immediate read count */ + unsigned totalcount; /* total read count (from this offset)*/ +}; + +/* + * Status OK portion of remote read reply + */ +struct readokres { + fattr attributes; /* attributes, need for pagin*/ + opaque data; +}; + +union readres switch (nfsstat status) { +case NFS_OK: + readokres reply; +default: + void; +}; + +/* + * Arguments to remote write + */ +struct writeargs { + nfs_fh file; /* handle for file */ + unsigned beginoffset; /* beginning byte offset in file */ + unsigned offset; /* current byte offset in file */ + unsigned totalcount; /* total write count (to this offset)*/ + opaque data; +}; + +struct createargs { + diropargs where; + sattr attributes; +}; + +struct renameargs { + diropargs from; + diropargs to; +}; + +struct linkargs { + nfs_fh from; + diropargs to; +}; + +struct symlinkargs { + diropargs from; + nfspath to; + sattr attributes; +}; + + +/* TS, 10/21/2002; converted cookie to struct */ +struct nfscookie { + opaque data[NFS_COOKIESIZE]; +}; + +/* + * Arguments to readdir + */ +struct readdirargs { + nfs_fh dir; /* directory handle */ + nfscookie cookie; + unsigned count; /* number of directory bytes to read */ +}; + +struct entry { + unsigned fileid; + filename name; + nfscookie cookie; + entry *nextentry; +}; + +struct dirlist { + entry *entries; + bool eof; +}; + +union readdirres switch (nfsstat status) { +case NFS_OK: + dirlist reply; +default: + void; +}; + +struct statfsokres { + unsigned tsize; /* preferred transfer size in bytes */ + unsigned bsize; /* fundamental file system block size */ + unsigned blocks; /* total blocks in file system */ + unsigned bfree; /* free blocks in fs */ + unsigned bavail; /* free blocks avail to non-superuser */ +}; + +union statfsres switch (nfsstat status) { +case NFS_OK: + statfsokres reply; +default: + void; +}; + +#ifdef WANT_NFS3 + +/* + * NFSv3 constants and types + */ +const NFS3_FHSIZE = 64; /* maximum size in bytes of a file handle */ +const NFS3_COOKIEVERFSIZE = 8; /* size of a cookie verifier for READDIR */ +const NFS3_CREATEVERFSIZE = 8; /* size of the verifier used for CREATE */ +const NFS3_WRITEVERFSIZE = 8; /* size of the verifier used for WRITE */ + +typedef unsigned hyper uint64; +typedef hyper int64; +typedef unsigned long uint32; +typedef long int32; +typedef string filename3<>; +typedef string nfspath3<>; +typedef uint64 fileid3; +typedef uint64 cookie3; +typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; +typedef opaque createverf3[NFS3_CREATEVERFSIZE]; +typedef opaque writeverf3[NFS3_WRITEVERFSIZE]; +typedef uint32 uid3; +typedef uint32 gid3; +typedef uint64 size3; +typedef uint64 offset3; +typedef uint32 mode3; +typedef uint32 count3; + +/* + * Error status (v3) + */ +enum nfsstat3 { + NFS3_OK = 0, + NFS3ERR_PERM = 1, + NFS3ERR_NOENT = 2, + NFS3ERR_IO = 5, + NFS3ERR_NXIO = 6, + NFS3ERR_ACCES = 13, + NFS3ERR_EXIST = 17, + NFS3ERR_XDEV = 18, + NFS3ERR_NODEV = 19, + NFS3ERR_NOTDIR = 20, + NFS3ERR_ISDIR = 21, + NFS3ERR_INVAL = 22, + NFS3ERR_FBIG = 27, + NFS3ERR_NOSPC = 28, + NFS3ERR_ROFS = 30, + NFS3ERR_MLINK = 31, + NFS3ERR_NAMETOOLONG = 63, + NFS3ERR_NOTEMPTY = 66, + NFS3ERR_DQUOT = 69, + NFS3ERR_STALE = 70, + NFS3ERR_REMOTE = 71, + NFS3ERR_BADHANDLE = 10001, + NFS3ERR_NOT_SYNC = 10002, + NFS3ERR_BAD_COOKIE = 10003, + NFS3ERR_NOTSUPP = 10004, + NFS3ERR_TOOSMALL = 10005, + NFS3ERR_SERVERFAULT = 10006, + NFS3ERR_BADTYPE = 10007, + NFS3ERR_JUKEBOX = 10008 +}; + +/* + * File types (v3) + */ +enum ftype3 { + NF3REG = 1, /* regular file */ + NF3DIR = 2, /* directory */ + NF3BLK = 3, /* block special */ + NF3CHR = 4, /* character special */ + NF3LNK = 5, /* symbolic link */ + NF3SOCK = 6, /* unix domain sockets */ + NF3FIFO = 7 /* named pipe */ +}; + +struct specdata3 { + uint32 specdata1; + uint32 specdata2; +}; + +/* + * File access handle (v3) + */ +struct nfs_fh3 { + opaque data; +}; + +/* + * Timeval (v3) + */ +struct nfstime3 { + uint32 seconds; + uint32 nseconds; +}; + + +/* + * File attributes (v3) + */ +struct fattr3 { + ftype3 type; /* file type */ + mode3 mode; /* protection mode bits */ + uint32 nlink; /* # hard links */ + uid3 uid; /* owner user id */ + gid3 gid; /* owner group id */ + size3 size; /* file size in bytes */ + size3 used; /* prefered block size */ + specdata3 rdev; /* special device # */ + uint64 fsid; /* device # */ + fileid3 fileid; /* inode # */ + nfstime3 atime; /* time of last access */ + nfstime3 mtime; /* time of last modification */ + nfstime3 ctime; /* time of last change */ +}; + +union post_op_attr switch (bool attributes_follow) { +case TRUE: + fattr3 attributes; +case FALSE: + void; +}; + +struct wcc_attr { + size3 size; + nfstime3 mtime; + nfstime3 ctime; +}; + +union pre_op_attr switch (bool attributes_follow) { +case TRUE: + wcc_attr attributes; +case FALSE: + void; +}; + +struct wcc_data { + pre_op_attr before; + post_op_attr after; +}; + +union post_op_fh3 switch (bool handle_follows) { +case TRUE: + nfs_fh3 handle; +case FALSE: + void; +}; + +/* + * File attributes which can be set (v3) + */ +enum time_how { + DONT_CHANGE = 0, + SET_TO_SERVER_TIME = 1, + SET_TO_CLIENT_TIME = 2 +}; + +union set_mode3 switch (bool set_it) { +case TRUE: + mode3 mode; +default: + void; +}; + +union set_uid3 switch (bool set_it) { +case TRUE: + uid3 uid; +default: + void; +}; + +union set_gid3 switch (bool set_it) { +case TRUE: + gid3 gid; +default: + void; +}; + +union set_size3 switch (bool set_it) { +case TRUE: + size3 size; +default: + void; +}; + +union set_atime switch (time_how set_it) { +case SET_TO_CLIENT_TIME: + nfstime3 atime; +default: + void; +}; + +union set_mtime switch (time_how set_it) { +case SET_TO_CLIENT_TIME: + nfstime3 mtime; +default: + void; +}; + +struct sattr3 { + set_mode3 mode; + set_uid3 uid; + set_gid3 gid; + set_size3 size; + set_atime atime; + set_mtime mtime; +}; + +/* + * Arguments for directory operations (v3) + */ +struct diropargs3 { + nfs_fh3 dir; /* directory file handle */ + filename3 name; /* name (up to NFS_MAXNAMLEN bytes) */ +}; + +/* + * Arguments to getattr (v3). + */ +struct GETATTR3args { + nfs_fh3 object; +}; + +struct GETATTR3resok { + fattr3 obj_attributes; +}; + +union GETATTR3res switch (nfsstat3 status) { +case NFS3_OK: + GETATTR3resok resok; +default: + void; +}; + +/* + * Arguments to setattr (v3). + */ +union sattrguard3 switch (bool check) { +case TRUE: + nfstime3 obj_ctime; +case FALSE: + void; +}; + +struct SETATTR3args { + nfs_fh3 object; + sattr3 new_attributes; + sattrguard3 guard; +}; + +struct SETATTR3resok { + wcc_data obj_wcc; +}; + +struct SETATTR3resfail { + wcc_data obj_wcc; +}; + +union SETATTR3res switch (nfsstat3 status) { +case NFS3_OK: + SETATTR3resok resok; +default: + SETATTR3resfail resfail; +}; + +/* + * Arguments to lookup (v3). + */ +struct LOOKUP3args { + diropargs3 what; +}; + +struct LOOKUP3resok { + nfs_fh3 object; + post_op_attr obj_attributes; + post_op_attr dir_attributes; +}; + +struct LOOKUP3resfail { + post_op_attr dir_attributes; +}; + +union LOOKUP3res switch (nfsstat3 status) { +case NFS3_OK: + LOOKUP3resok resok; +default: + LOOKUP3resfail resfail; +}; + +/* + * Arguments to access (v3). + */ +const ACCESS3_READ = 0x0001; +const ACCESS3_LOOKUP = 0x0002; +const ACCESS3_MODIFY = 0x0004; +const ACCESS3_EXTEND = 0x0008; +const ACCESS3_DELETE = 0x0010; +const ACCESS3_EXECUTE = 0x0020; + +struct ACCESS3args { + nfs_fh3 object; + uint32 access; +}; + +struct ACCESS3resok { + post_op_attr obj_attributes; + uint32 access; +}; + +struct ACCESS3resfail { + post_op_attr obj_attributes; +}; + +union ACCESS3res switch (nfsstat3 status) { +case NFS3_OK: + ACCESS3resok resok; +default: + ACCESS3resfail resfail; +}; + +/* + * Arguments to readlink (v3). + */ +struct READLINK3args { + nfs_fh3 symlink; +}; + +struct READLINK3resok { + post_op_attr symlink_attributes; + nfspath3 data; +}; + +struct READLINK3resfail { + post_op_attr symlink_attributes; +}; + +union READLINK3res switch (nfsstat3 status) { +case NFS3_OK: + READLINK3resok resok; +default: + READLINK3resfail resfail; +}; + +/* + * Arguments to read (v3). + */ +struct READ3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; + +struct READ3resok { + post_op_attr file_attributes; + count3 count; + bool eof; + opaque data<>; +}; + +struct READ3resfail { + post_op_attr file_attributes; +}; + +/* XXX: solaris 2.6 uses ``nfsstat'' here */ +union READ3res switch (nfsstat3 status) { +case NFS3_OK: + READ3resok resok; +default: + READ3resfail resfail; +}; + +/* + * Arguments to write (v3). + */ +enum stable_how { + UNSTABLE = 0, + DATA_SYNC = 1, + FILE_SYNC = 2 +}; + +struct WRITE3args { + nfs_fh3 file; + offset3 offset; + count3 count; + stable_how stable; + opaque data<>; +}; + +struct WRITE3resok { + wcc_data file_wcc; + count3 count; + stable_how committed; + writeverf3 verf; +}; + +struct WRITE3resfail { + wcc_data file_wcc; +}; + +union WRITE3res switch (nfsstat3 status) { +case NFS3_OK: + WRITE3resok resok; +default: + WRITE3resfail resfail; +}; + +/* + * Arguments to create (v3). + */ +enum createmode3 { + UNCHECKED = 0, + GUARDED = 1, + EXCLUSIVE = 2 +}; + +union createhow3 switch (createmode3 mode) { +case UNCHECKED: +case GUARDED: + sattr3 obj_attributes; +case EXCLUSIVE: + createverf3 verf; +}; + +struct CREATE3args { + diropargs3 where; + createhow3 how; +}; + +struct CREATE3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct CREATE3resfail { + wcc_data dir_wcc; +}; + +union CREATE3res switch (nfsstat3 status) { +case NFS3_OK: + CREATE3resok resok; +default: + CREATE3resfail resfail; +}; + +/* + * Arguments to mkdir (v3). + */ +struct MKDIR3args { + diropargs3 where; + sattr3 attributes; +}; + +struct MKDIR3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct MKDIR3resfail { + wcc_data dir_wcc; +}; + +union MKDIR3res switch (nfsstat3 status) { +case NFS3_OK: + MKDIR3resok resok; +default: + MKDIR3resfail resfail; +}; + +/* + * Arguments to symlink (v3). + */ +struct symlinkdata3 { + sattr3 symlink_attributes; + nfspath3 symlink_data; +}; + +struct SYMLINK3args { + diropargs3 where; + symlinkdata3 symlink; +}; + +struct SYMLINK3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct SYMLINK3resfail { + wcc_data dir_wcc; +}; + +union SYMLINK3res switch (nfsstat3 status) { +case NFS3_OK: + SYMLINK3resok resok; +default: + SYMLINK3resfail resfail; +}; + +/* + * Arguments to mknod (v3). + */ +struct devicedata3 { + sattr3 dev_attributes; + specdata3 spec; +}; + +union mknoddata3 switch (ftype3 type) { +case NF3CHR: +case NF3BLK: + devicedata3 device; +case NF3SOCK: +case NF3FIFO: + sattr3 pipe_attributes; +default: + void; +}; + +struct MKNOD3args { + diropargs3 where; + mknoddata3 what; +}; + +struct MKNOD3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct MKNOD3resfail { + wcc_data dir_wcc; +}; + +union MKNOD3res switch (nfsstat3 status) { +case NFS3_OK: + MKNOD3resok resok; +default: + MKNOD3resfail resfail; +}; + +/* + * Arguments to remove (v3). + */ +struct REMOVE3args { + diropargs3 object; +}; + +struct REMOVE3resok { + wcc_data dir_wcc; +}; + +struct REMOVE3resfail { + wcc_data dir_wcc; +}; + +union REMOVE3res switch (nfsstat3 status) { +case NFS3_OK: + REMOVE3resok resok; +default: + REMOVE3resfail resfail; +}; + +/* + * Arguments to rmdir (v3). + */ +struct RMDIR3args { + diropargs3 object; +}; + +struct RMDIR3resok { + wcc_data dir_wcc; +}; + +struct RMDIR3resfail { + wcc_data dir_wcc; +}; + +union RMDIR3res switch (nfsstat3 status) { +case NFS3_OK: + RMDIR3resok resok; +default: + RMDIR3resfail resfail; +}; + +/* + * Arguments to rename (v3). + */ +struct RENAME3args { + diropargs3 from; + diropargs3 to; +}; + +struct RENAME3resok { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; + +struct RENAME3resfail { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; + +union RENAME3res switch (nfsstat3 status) { +case NFS3_OK: + RENAME3resok resok; +default: + RENAME3resfail resfail; +}; + +/* + * Arguments to link (v3). + */ +struct LINK3args { + nfs_fh3 file; + diropargs3 link; +}; + +struct LINK3resok { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; + +struct LINK3resfail { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; + +union LINK3res switch (nfsstat3 status) { +case NFS3_OK: + LINK3resok resok; +default: + LINK3resfail resfail; +}; + +/* + * Arguments to readdir (v3). + */ +struct READDIR3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 count; +}; + +struct entry3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + entry3 *nextentry; +}; + +struct dirlist3 { + entry3 *entries; + bool eof; +}; + +struct READDIR3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlist3 reply; +}; + +struct READDIR3resfail { + post_op_attr dir_attributes; +}; + +union READDIR3res switch (nfsstat3 status) { +case NFS3_OK: + READDIR3resok resok; +default: + READDIR3resfail resfail; +}; + +/* + * Arguments to readdirplus (v3). + */ +struct READDIRPLUS3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 dircount; + count3 maxcount; +}; + +struct entryplus3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + post_op_attr name_attributes; + post_op_fh3 name_handle; + entryplus3 *nextentry; +}; + +struct dirlistplus3 { + entryplus3 *entries; + bool eof; +}; + +struct READDIRPLUS3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlistplus3 reply; +}; + +struct READDIRPLUS3resfail { + post_op_attr dir_attributes; +}; + +union READDIRPLUS3res switch (nfsstat3 status) { +case NFS3_OK: + READDIRPLUS3resok resok; +default: + READDIRPLUS3resfail resfail; +}; + +/* + * Arguments to fsstat (v3). + */ +struct FSSTAT3args { + nfs_fh3 fsroot; +}; + +struct FSSTAT3resok { + post_op_attr obj_attributes; + size3 tbytes; + size3 fbytes; + size3 abytes; + size3 tfiles; + size3 ffiles; + size3 afiles; + uint32 invarsec; +}; + +struct FSSTAT3resfail { + post_op_attr obj_attributes; +}; + +union FSSTAT3res switch (nfsstat3 status) { +case NFS3_OK: + FSSTAT3resok resok; +default: + FSSTAT3resfail resfail; +}; + +/* + * Arguments to fsinfo (v3). + */ +const FSF3_LINK = 0x0001; +const FSF3_SYMLINK = 0x0002; +const FSF3_HOMOGENEOUS = 0x0008; +const FSF3_CANSETTIME = 0x0010; + +struct FSINFO3args { + nfs_fh3 fsroot; +}; + +struct FSINFO3resok { + post_op_attr obj_attributes; + uint32 rtmax; + uint32 rtpref; + uint32 rtmult; + uint32 wtmax; + uint32 wtpref; + uint32 wtmult; + uint32 dtpref; + size3 maxfilesize; + nfstime3 time_delta; + uint32 properties; +}; + +struct FSINFO3resfail { + post_op_attr obj_attributes; +}; + +union FSINFO3res switch (nfsstat3 status) { +case NFS3_OK: + FSINFO3resok resok; +default: + FSINFO3resfail resfail; +}; + +/* + * Arguments to pathconf (v3). + */ +struct PATHCONF3args { + nfs_fh3 object; +}; + +struct PATHCONF3resok { + post_op_attr obj_attributes; + uint32 linkmax; + uint32 name_max; + bool no_trunc; + bool chown_restricted; + bool case_insensitive; + bool case_preserving; +}; + +struct PATHCONF3resfail { + post_op_attr obj_attributes; +}; + +union PATHCONF3res switch (nfsstat3 status) { +case NFS3_OK: + PATHCONF3resok resok; +default: + PATHCONF3resfail resfail; +}; + +/* + * Arguments to commit (v3). + */ +struct COMMIT3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; + +struct COMMIT3resok { + wcc_data file_wcc; + writeverf3 verf; +}; + +struct COMMIT3resfail { + wcc_data file_wcc; +}; + +union COMMIT3res switch (nfsstat3 status) { +case NFS3_OK: + COMMIT3resok resok; +default: + COMMIT3resfail resfail; +}; + +#endif /* WANT_NFS3 */ + +/* + * Remote file service routines + */ +program NFS_PROGRAM { + version NFS_VERSION { + void + NFSPROC_NULL(void) = 0; + + attrstat + NFSPROC_GETATTR(nfs_fh) = 1; + + attrstat + NFSPROC_SETATTR(sattrargs) = 2; + + void + NFSPROC_ROOT(void) = 3; + + diropres + NFSPROC_LOOKUP(diropargs) = 4; + + readlinkres + NFSPROC_READLINK(nfs_fh) = 5; + + readres + NFSPROC_READ(readargs) = 6; + + void + NFSPROC_WRITECACHE(void) = 7; + + attrstat + NFSPROC_WRITE(writeargs) = 8; + + diropres + NFSPROC_CREATE(createargs) = 9; + + nfsstat + NFSPROC_REMOVE(diropargs) = 10; + + nfsstat + NFSPROC_RENAME(renameargs) = 11; + + nfsstat + NFSPROC_LINK(linkargs) = 12; + + nfsstat + NFSPROC_SYMLINK(symlinkargs) = 13; + + diropres + NFSPROC_MKDIR(createargs) = 14; + + nfsstat + NFSPROC_RMDIR(diropargs) = 15; + + readdirres + NFSPROC_READDIR(readdirargs) = 16; + + statfsres + NFSPROC_STATFS(nfs_fh) = 17; + } = 2; +} = 100003; +#ifdef WANT_NFS3 +program NFS3_PROGRAM { + version NFS_V3 { + void + NFSPROC3_NULL(void) = 0; + + GETATTR3res + NFSPROC3_GETATTR(GETATTR3args) = 1; + + SETATTR3res + NFSPROC3_SETATTR(SETATTR3args) = 2; + + LOOKUP3res + NFSPROC3_LOOKUP(LOOKUP3args) = 3; + + ACCESS3res + NFSPROC3_ACCESS(ACCESS3args) = 4; + + READLINK3res + NFSPROC3_READLINK(READLINK3args) = 5; + + READ3res + NFSPROC3_READ(READ3args) = 6; + + WRITE3res + NFSPROC3_WRITE(WRITE3args) = 7; + + CREATE3res + NFSPROC3_CREATE(CREATE3args) = 8; + + MKDIR3res + NFSPROC3_MKDIR(MKDIR3args) = 9; + + SYMLINK3res + NFSPROC3_SYMLINK(SYMLINK3args) = 10; + + MKNOD3res + NFSPROC3_MKNOD(MKNOD3args) = 11; + + REMOVE3res + NFSPROC3_REMOVE(REMOVE3args) = 12; + + RMDIR3res + NFSPROC3_RMDIR(RMDIR3args) = 13; + + RENAME3res + NFSPROC3_RENAME(RENAME3args) = 14; + + LINK3res + NFSPROC3_LINK(LINK3args) = 15; + + READDIR3res + NFSPROC3_READDIR(READDIR3args) = 16; + + READDIRPLUS3res + NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17; + + FSSTAT3res + NFSPROC3_FSSTAT(FSSTAT3args) = 18; + + FSINFO3res + NFSPROC3_FSINFO(FSINFO3args) = 19; + + PATHCONF3res + NFSPROC3_PATHCONF(PATHCONF3args) = 20; + + COMMIT3res + NFSPROC3_COMMIT(COMMIT3args) = 21; + } = 3; +} = 100003; +#endif + diff --git a/rtemsNfs/proto/nfs_prot_xdr.c b/rtemsNfs/proto/nfs_prot_xdr.c new file mode 100644 index 0000000..7e222ec --- /dev/null +++ b/rtemsNfs/proto/nfs_prot_xdr.c @@ -0,0 +1,671 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfs_prot.h" +#ifndef lint +/*static char sccsid[] = "from: @(#)nfs_prot.x 1.2 87/10/12 Copyr 1987 Sun Micro";*/ +/*static char sccsid[] = "from: @(#)nfs_prot.x 2.1 88/08/01 4.0 RPCSRC";*/ +static char rcsid[] = "$Id$"; +#endif /* not lint */ + +bool_t +xdr_nfsstat (XDR *xdrs, nfsstat *objp) +{ + register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ftype (XDR *xdrs, ftype *objp) +{ + register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_fh (XDR *xdrs, nfs_fh *objp) +{ + register int32_t *buf; + + int i; + if (!xdr_opaque (xdrs, objp->data, NFS_FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfstime (XDR *xdrs, nfstime *objp) +{ + register int32_t *buf; + + if (!xdr_u_int (xdrs, &objp->seconds)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->useconds)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fattr (XDR *xdrs, fattr *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_ftype (xdrs, &objp->type)) + return FALSE; + buf = XDR_INLINE (xdrs, 10 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->mode); + IXDR_PUT_U_LONG(buf, objp->nlink); + IXDR_PUT_U_LONG(buf, objp->uid); + IXDR_PUT_U_LONG(buf, objp->gid); + IXDR_PUT_U_LONG(buf, objp->size); + IXDR_PUT_U_LONG(buf, objp->blocksize); + IXDR_PUT_U_LONG(buf, objp->rdev); + IXDR_PUT_U_LONG(buf, objp->blocks); + IXDR_PUT_U_LONG(buf, objp->fsid); + IXDR_PUT_U_LONG(buf, objp->fileid); + } + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->ctime)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_ftype (xdrs, &objp->type)) + return FALSE; + buf = XDR_INLINE (xdrs, 10 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + + } else { + objp->mode = IXDR_GET_U_LONG(buf); + objp->nlink = IXDR_GET_U_LONG(buf); + objp->uid = IXDR_GET_U_LONG(buf); + objp->gid = IXDR_GET_U_LONG(buf); + objp->size = IXDR_GET_U_LONG(buf); + objp->blocksize = IXDR_GET_U_LONG(buf); + objp->rdev = IXDR_GET_U_LONG(buf); + objp->blocks = IXDR_GET_U_LONG(buf); + objp->fsid = IXDR_GET_U_LONG(buf); + objp->fileid = IXDR_GET_U_LONG(buf); + } + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->ctime)) + return FALSE; + return TRUE; + } + + if (!xdr_ftype (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_sattr (XDR *xdrs, sattr *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->mode); + IXDR_PUT_U_LONG(buf, objp->uid); + IXDR_PUT_U_LONG(buf, objp->gid); + IXDR_PUT_U_LONG(buf, objp->size); + } + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + + } else { + objp->mode = IXDR_GET_U_LONG(buf); + objp->uid = IXDR_GET_U_LONG(buf); + objp->gid = IXDR_GET_U_LONG(buf); + objp->size = IXDR_GET_U_LONG(buf); + } + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime (xdrs, &objp->mtime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_filename (XDR *xdrs, filename *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, objp, NFS_MAXNAMLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfspath (XDR *xdrs, nfspath *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, objp, NFS_MAXPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_attrstat (XDR *xdrs, attrstat *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_fattr (xdrs, &objp->attrstat_u.attributes)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_sattrargs (XDR *xdrs, sattrargs *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + if (!xdr_sattr (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_diropargs (XDR *xdrs, diropargs *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->dir)) + return FALSE; + if (!xdr_filename (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_diropokres (XDR *xdrs, diropokres *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + if (!xdr_fattr (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_diropres (XDR *xdrs, diropres *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_diropokres (xdrs, &objp->diropres_u.diropres)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_readlinkres (XDR *xdrs, readlinkres *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_nfspath (xdrs, &objp->readlinkres_u.data)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_readargs (XDR *xdrs, readargs *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->count)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + return TRUE; +} + +bool_t +xdr_readokres (XDR *xdrs, readokres *objp) +{ + register int32_t *buf; + + if (!xdr_fattr (xdrs, &objp->attributes)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS_MAXDATA)) + return FALSE; + return TRUE; +} + +bool_t +xdr_readres (XDR *xdrs, readres *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_readokres (xdrs, &objp->readres_u.reply)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_writeargs (XDR *xdrs, writeargs *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->beginoffset); + IXDR_PUT_U_LONG(buf, objp->offset); + IXDR_PUT_U_LONG(buf, objp->totalcount); + } + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS_MAXDATA)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + + } else { + objp->beginoffset = IXDR_GET_U_LONG(buf); + objp->offset = IXDR_GET_U_LONG(buf); + objp->totalcount = IXDR_GET_U_LONG(buf); + } + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS_MAXDATA)) + return FALSE; + return TRUE; + } + + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS_MAXDATA)) + return FALSE; + return TRUE; +} + +bool_t +xdr_createargs (XDR *xdrs, createargs *objp) +{ + register int32_t *buf; + + if (!xdr_diropargs (xdrs, &objp->where)) + return FALSE; + if (!xdr_sattr (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_renameargs (XDR *xdrs, renameargs *objp) +{ + register int32_t *buf; + + if (!xdr_diropargs (xdrs, &objp->from)) + return FALSE; + if (!xdr_diropargs (xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t +xdr_linkargs (XDR *xdrs, linkargs *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->from)) + return FALSE; + if (!xdr_diropargs (xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t +xdr_symlinkargs (XDR *xdrs, symlinkargs *objp) +{ + register int32_t *buf; + + if (!xdr_diropargs (xdrs, &objp->from)) + return FALSE; + if (!xdr_nfspath (xdrs, &objp->to)) + return FALSE; + if (!xdr_sattr (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfscookie (XDR *xdrs, nfscookie *objp) +{ + register int32_t *buf; + + int i; + if (!xdr_opaque (xdrs, objp->data, NFS_COOKIESIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_readdirargs (XDR *xdrs, readdirargs *objp) +{ + register int32_t *buf; + + if (!xdr_nfs_fh (xdrs, &objp->dir)) + return FALSE; + if (!xdr_nfscookie (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t +xdr_entry (XDR *xdrs, entry *objp) +{ + register int32_t *buf; + + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename (xdrs, &objp->name)) + return FALSE; + if (!xdr_nfscookie (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entry), (xdrproc_t) xdr_entry)) + return FALSE; + return TRUE; +} + +bool_t +xdr_dirlist (XDR *xdrs, dirlist *objp) +{ + register int32_t *buf; + + if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entry), (xdrproc_t) xdr_entry)) + return FALSE; + if (!xdr_bool (xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t +xdr_readdirres (XDR *xdrs, readdirres *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_dirlist (xdrs, &objp->readdirres_u.reply)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_statfsokres (XDR *xdrs, statfsokres *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + } else { + IXDR_PUT_U_LONG(buf, objp->tsize); + IXDR_PUT_U_LONG(buf, objp->bsize); + IXDR_PUT_U_LONG(buf, objp->blocks); + IXDR_PUT_U_LONG(buf, objp->bfree); + IXDR_PUT_U_LONG(buf, objp->bavail); + } + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + } else { + objp->tsize = IXDR_GET_U_LONG(buf); + objp->bsize = IXDR_GET_U_LONG(buf); + objp->blocks = IXDR_GET_U_LONG(buf); + objp->bfree = IXDR_GET_U_LONG(buf); + objp->bavail = IXDR_GET_U_LONG(buf); + } + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + return TRUE; +} + +bool_t +xdr_statfsres (XDR *xdrs, statfsres *objp) +{ + register int32_t *buf; + + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_statfsokres (xdrs, &objp->statfsres_u.reply)) + return FALSE; + break; + default: + break; + } + return TRUE; +} diff --git a/rtemsNfs/rtems-filesystem-patch b/rtemsNfs/rtems-filesystem-patch new file mode 100644 index 0000000..c2d7861 --- /dev/null +++ b/rtemsNfs/rtems-filesystem-patch @@ -0,0 +1,860 @@ +# Diffed against OAR_orig (ss-20020301) on Sun Nov 3 00:24:13 PST 2002 +# T.S. + +For more information about this patch consult README (CAVEATS section). + +To apply this patch, + +chdir to c/src/lib/libc + +and issue + + patch -p0 < this_file + +It is always a good idea to try a "dry-run" before applying a patch: + + patch --dry-run -p0 < this_file + +Index: Makefile.am +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/Makefile.am,v +retrieving revision 1.1.1.2 +retrieving revision 1.2 +diff -c -r1.1.1.2 -r1.2 +*** Makefile.am 7 Mar 2002 01:53:46 -0000 1.1.1.2 +--- Makefile.am 28 Mar 2002 20:59:16 -0000 1.2 +*************** +*** 1,5 **** + ## +! ## $Id$ + ## + + AUTOMAKE_OPTIONS = foreign 1.4 +--- 1,5 ---- + ## +! ## $Id$ + ## + + AUTOMAKE_OPTIONS = foreign 1.4 +*************** +*** 32,37 **** +--- 32,39 ---- + + MALLOC_C_FILES = malloc.c mallocfreespace.c __brk.c __sbrk.c + ++ ENVIRON_C_FILES = envlock.c ++ + PASSWORD_GROUP_C_FILES = getpwent.c getgrent.c + + TERMINAL_IDENTIFICATION_C_FILES = ctermid.c isatty.c ttyname.c ttyname_r.c +*************** +*** 42,48 **** + UNIX_LIBC_C_FILES = unixlibc.c hosterr.c + + COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ +! $(MALLOC_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ + $(ASSOCIATION_C_FILES) + + UNIX_C_FILES = $(UNIX_LIBC_C_FILES) +--- 44,50 ---- + UNIX_LIBC_C_FILES = unixlibc.c hosterr.c + + COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ +! $(MALLOC_C_FILES) $(ENVIRON_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ + $(ASSOCIATION_C_FILES) + + UNIX_C_FILES = $(UNIX_LIBC_C_FILES) +Index: base_fs.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/base_fs.c,v +retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 base_fs.c +*** base_fs.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 +--- base_fs.c 26 Oct 2002 02:45:15 -0000 +*************** +*** 49,54 **** +--- 49,55 ---- + int status; + rtems_filesystem_mount_table_entry_t *entry; + rtems_filesystem_mount_table_t *mt; ++ rtems_filesystem_location_info_t loc; + + /* + * Set the default umask to "022". +*************** +*** 75,82 **** + rtems_fatal_error_occurred( 0xABCD0002 ); + + rtems_filesystem_link_counts = 0; + rtems_filesystem_root = entry->mt_fs_root; +! rtems_filesystem_current = rtems_filesystem_root; + + + /* +--- 76,113 ---- + rtems_fatal_error_occurred( 0xABCD0002 ); + + rtems_filesystem_link_counts = 0; ++ ++ /* setup the 'current' and 'root' directories ++ * ++ * NOTE: cloning the pathlocs is not strictly ++ * necessary. Since we implicitely let ++ * all threads that don't call ++ * libio_set_private_env() share the same ++ * (initial) 'root' and 'current' locs, ++ * we (also implicitely) assume that the ++ * root filesystem doesn't care about ++ * reference counts. ++ * I just inserted the code snippet below ++ * to remind everybody of the fact by ++ * making it more explicit... ++ * Ideally, every thread would have to ++ * call either share_private_env() or ++ * set_private_env() - but then: that's ++ * gonna hit performance. ++ * ++ * Till Straumann, 10/25/2002 ++ */ + rtems_filesystem_root = entry->mt_fs_root; +! /* Clone the root pathloc */ +! rtems_filesystem_evaluate_path("/", 0, &loc, 0); +! rtems_filesystem_root = loc; +! /* One more clone for the current node */ +! rtems_filesystem_evaluate_path("/", 0, &loc, 0); +! rtems_filesystem_current = loc; +! +! /* Note: the global_env's refcnt doesn't matter +! * as the global env is never released +! */ + + + /* +Index: chroot.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/chroot.c,v +retrieving revision 1.1.1.2 +diff -c -r1.1.1.2 chroot.c +*** chroot.c 7 Mar 2002 01:53:47 -0000 1.1.1.2 +--- chroot.c 29 Oct 2002 03:01:47 -0000 +*************** +*** 38,51 **** + rtems_set_errno_and_return_minus_one( ENOTSUP ); + }; + +- loc = rtems_filesystem_root; /* save the value */ +- + result = chdir(pathname); + if (result) { +- rtems_filesystem_root = loc; /* restore the value */ + rtems_set_errno_and_return_minus_one( errno ); + }; +! rtems_filesystem_root = rtems_filesystem_current; + + return 0; + } +--- 38,53 ---- + rtems_set_errno_and_return_minus_one( ENOTSUP ); + }; + + result = chdir(pathname); + if (result) { + rtems_set_errno_and_return_minus_one( errno ); + }; +! /* clone the new root location */ +! if (rtems_filesystem_evaluate_path(".", 0, &loc, 0)) { +! rtems_set_errno_and_return_minus_one( errno ); +! } +! rtems_filesystem_freenode(&rtems_filesystem_root); +! rtems_filesystem_root = loc; + + return 0; + } +Index: eval.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/eval.c,v +retrieving revision 1.1.1.2 +retrieving revision 1.2 +diff -c -r1.1.1.2 -r1.2 +*** eval.c 7 Mar 2002 01:53:48 -0000 1.1.1.2 +--- eval.c 29 Oct 2002 21:03:50 -0000 1.2 +*************** +*** 10,16 **** + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +--- 10,16 ---- + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +*************** +*** 60,76 **** + + if ( (result == 0) && follow_link ) { + +! if ( !pathloc->ops->node_type_h ) + rtems_set_errno_and_return_minus_one( ENOTSUP ); + + type = (*pathloc->ops->node_type_h)( pathloc ); + + if ( ( type == RTEMS_FILESYSTEM_HARD_LINK ) || + ( type == RTEMS_FILESYSTEM_SYM_LINK ) ) { + +! if ( !pathloc->ops->eval_link_h ) + rtems_set_errno_and_return_minus_one( ENOTSUP ); + + result = (*pathloc->ops->eval_link_h)( pathloc, flags ); + + } +--- 60,93 ---- + + if ( (result == 0) && follow_link ) { + +! if ( !pathloc->ops->node_type_h ) { +! rtems_filesystem_freenode(pathloc); + rtems_set_errno_and_return_minus_one( ENOTSUP ); ++ } + + type = (*pathloc->ops->node_type_h)( pathloc ); + + if ( ( type == RTEMS_FILESYSTEM_HARD_LINK ) || + ( type == RTEMS_FILESYSTEM_SYM_LINK ) ) { + +! if ( !pathloc->ops->eval_link_h ) { +! rtems_filesystem_freenode(pathloc); + rtems_set_errno_and_return_minus_one( ENOTSUP ); ++ } + ++ /* what to do with the valid node pathloc points to ++ * if eval_link_h() fails? ++ * Let the FS implementation deal with this case. It ++ * should probably free pathloc in either case: ++ * - if the link evaluation fails, it must free the ++ * original (valid) pathloc because we are going ++ * to return -1 and hence the FS generics won't ++ * cleanup pathloc ++ * - if the link evaluation is successful, the updated ++ * pathloc will be passed up (and eventually released). ++ * Hence, the (valid) original node that we submit to ++ * eval_link_h() should be released by the handler. ++ */ + result = (*pathloc->ops->eval_link_h)( pathloc, flags ); + + } +Index: fchdir.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/fchdir.c,v +retrieving revision 1.1.1.2 +diff -c -r1.1.1.2 fchdir.c +*** fchdir.c 7 Mar 2002 01:53:48 -0000 1.1.1.2 +--- fchdir.c 25 Oct 2002 23:59:03 -0000 +*************** +*** 29,34 **** +--- 29,35 ---- + ) + { + rtems_libio_t *iop; ++ rtems_filesystem_location_info_t loc; + + rtems_libio_check_fd( fd ); + iop = rtems_libio_iop( fd ); +*************** +*** 65,74 **** + * this node which we are making here. I can + * see the freenode interface but do not see + * allocnode node interface. It maybe node_type. + */ + + rtems_filesystem_current = iop->pathinfo; + + return 0; + } +- +--- 66,80 ---- + * this node which we are making here. I can + * see the freenode interface but do not see + * allocnode node interface. It maybe node_type. ++ * ++ * FIXEC: T.Straumann: it is evaluate_path() + */ + + rtems_filesystem_current = iop->pathinfo; + ++ /* clone the current node */ ++ rtems_filesystem_evaluate_path(".", 0, &loc, 0); ++ rtems_filesystem_current = loc; ++ + return 0; + } +Index: getgrent.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/getgrent.c,v +retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 getgrent.c +*** getgrent.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 +--- getgrent.c 27 Oct 2002 18:24:20 -0000 +*************** +*** 50,63 **** +--- 50,69 ---- + ) + { + FILE *fp; ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if ((fp = fopen ("/etc/group", "r")) == NULL) { + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 72,84 **** +--- 78,94 ---- + if (!strcmp (groupname, name)) { + fclose (fp); + *result = grp; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return 0; + } + } + fclose (fp); + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 104,118 **** +--- 114,134 ---- + ) + { + FILE *fp; ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + + + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if ((fp = fopen ("/etc/group", "r")) == NULL) { + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 128,140 **** +--- 144,160 ---- + if (gid == gr_group.gr_gid) { + fclose (fp); + *result = grp; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return 0; + } + } + fclose (fp); + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 174,188 **** +--- 194,214 ---- + void + setgrent () + { ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if (group_fp != NULL) + fclose (group_fp); + + group_fp = fopen ("/etc/group", "r"); ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + } + + void +Index: getpwent.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/getpwent.c,v +retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 getpwent.c +*** getpwent.c 14 Dec 2001 22:52:31 -0000 1.1.1.1 +--- getpwent.c 27 Oct 2002 18:18:52 -0000 +*************** +*** 97,110 **** +--- 97,116 ---- + ) + { + FILE *fp; ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if ((fp = fopen ("/etc/passwd", "r")) == NULL) { + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 123,135 **** +--- 129,145 ---- + if (!strcmp (logname, name)) { + fclose (fp); + *result = pwd; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return 0; + } + } + fclose (fp); + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 155,168 **** +--- 165,184 ---- + ) + { + FILE *fp; ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if ((fp = fopen ("/etc/passwd", "r")) == NULL) { + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 181,193 **** +--- 197,213 ---- + if (uid == pwd->pw_uid) { + fclose (fp); + *result = pwd; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return 0; + } + } + fclose (fp); + errno = EINVAL; ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + return -1; + } + +*************** +*** 230,244 **** +--- 250,270 ---- + + void setpwent( void ) + { ++ #if 0 + rtems_user_env_t * aux=rtems_current_user_env; /* save */ ++ #endif + init_etc_passwd_group(); ++ #if 0 + rtems_current_user_env=&rtems_global_user_env; /* set root */ ++ #endif + + if (passwd_fp != NULL) + fclose (passwd_fp); + + passwd_fp = fopen ("/etc/passwd", "r"); ++ #if 0 + rtems_current_user_env=aux; /* restore */ ++ #endif + } + + void endpwent( void ) +Index: mknod.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/mknod.c,v +retrieving revision 1.1.1.2 +retrieving revision 1.2 +diff -c -r1.1.1.2 -r1.2 +*** mknod.c 7 Mar 2002 01:53:51 -0000 1.1.1.2 +--- mknod.c 29 Oct 2002 21:03:50 -0000 1.2 +*************** +*** 12,18 **** + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +--- 12,18 ---- + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +*************** +*** 49,55 **** + rtems_filesystem_get_start_loc( pathname, &i, &temp_loc ); + + if ( !temp_loc.ops->evalformake_h ) { +- rtems_filesystem_freenode( &temp_loc ); + rtems_set_errno_and_return_minus_one( ENOTSUP ); + } + +--- 49,54 ---- +Index: mount.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/mount.c,v +retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 mount.c +*** mount.c 14 Dec 2001 22:52:33 -0000 1.1.1.1 +--- mount.c 30 Oct 2002 06:39:09 -0000 +*************** +*** 14,20 **** + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +--- 14,20 ---- + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + */ + + #if HAVE_CONFIG_H +*************** +*** 101,106 **** +--- 101,113 ---- + return -1; + } + ++ /* Do they support being mounted at all ? */ ++ if ( !fs_ops->fsmount_me_h ) { ++ errno = ENOTSUP; ++ goto cleanup_and_bail; ++ } ++ ++ + /* + * Allocate a mount table entry + */ +*************** +*** 140,145 **** +--- 147,158 ---- + */ + + loc_to_free = &loc; ++ ++ if ( !loc.ops->node_type_h ) { ++ errno = ENOTSUP; ++ goto cleanup_and_bail; ++ } ++ + if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { + errno = ENOTDIR; + goto cleanup_and_bail; +*************** +*** 198,210 **** + temp_mt_entry->mt_point_node.mt_entry = NULL; + } + +! if ( !fs_ops->fsmount_me_h ) { +! errno = ENOTSUP; + goto cleanup_and_bail; + } +- +- if ( fs_ops->fsmount_me_h( temp_mt_entry ) ) +- goto cleanup_and_bail; + + /* + * Add the mount table entry to the mount table chain +--- 211,223 ---- + temp_mt_entry->mt_point_node.mt_entry = NULL; + } + +! if ( fs_ops->fsmount_me_h( temp_mt_entry ) ) { +! /* try to undo the mount operation */ +! if ( loc.ops->unmount_h ) { +! loc.ops->unmount_h( temp_mt_entry ); +! } + goto cleanup_and_bail; + } + + /* + * Add the mount table entry to the mount table chain +Index: newlibc.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/newlibc.c,v +retrieving revision 1.1.1.1 +retrieving revision 1.3 +diff -c -r1.1.1.1 -r1.3 +*** newlibc.c 14 Dec 2001 22:52:33 -0000 1.1.1.1 +--- newlibc.c 16 Apr 2002 19:41:03 -0000 1.3 +*************** +*** 9,15 **** + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + * + */ + +--- 9,15 ---- + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * +! * $Id$ + * + */ + +Index: privateenv.c +=================================================================== +RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libc/privateenv.c,v +retrieving revision 1.1.1.2 +diff -c -r1.1.1.2 privateenv.c +*** privateenv.c 7 Mar 2002 01:53:51 -0000 1.1.1.2 +--- privateenv.c 27 Oct 2002 18:35:34 -0000 +*************** +*** 23,47 **** + #include + #include + + rtems_status_code rtems_libio_set_private_env(void) { +! rtems_status_code sc; +! rtems_id task_id; + + sc=rtems_task_ident(RTEMS_SELF,0,&task_id); + if (sc != RTEMS_SUCCESSFUL) return sc; + + /* Only for the first time a malloc is necesary */ +! if (rtems_current_user_env==&rtems_global_user_env) { +! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free); +! if (sc != RTEMS_SUCCESSFUL) return sc; +! rtems_current_user_env = malloc(sizeof(rtems_user_env_t)); +! if (!rtems_current_user_env) + return RTEMS_NO_MEMORY; + }; + +- /* the side effect desired . chroot("/") */ + *rtems_current_user_env = rtems_global_user_env; /* get the global values*/ + rtems_current_user_env->task_id=task_id; /* mark the local values*/ + + return RTEMS_SUCCESSFUL; + } +--- 23,92 ---- + #include + #include + ++ extern Chain_Control rtems_filesystem_mount_table_control; ++ ++ #define THE_ROOT_FS_LOC \ ++ (((rtems_filesystem_mount_table_entry_t*)\ ++ rtems_filesystem_mount_table_control.first)->mt_fs_root) ++ ++ /* cleanup a user environment ++ * NOTE: this must be called with ++ * thread dispatching disabled! ++ */ ++ static void ++ free_user_env(rtems_user_env_t *env) ++ { ++ if (env != &rtems_global_user_env ++ && --env->refcnt <= 0) { ++ rtems_filesystem_freenode( &env->current_directory); ++ rtems_filesystem_freenode( &env->root_directory); ++ free(env); ++ } ++ } ++ + rtems_status_code rtems_libio_set_private_env(void) { +! rtems_status_code sc; +! rtems_id task_id; +! rtems_filesystem_location_info_t loc; + + sc=rtems_task_ident(RTEMS_SELF,0,&task_id); + if (sc != RTEMS_SUCCESSFUL) return sc; + + /* Only for the first time a malloc is necesary */ +! if (rtems_current_user_env==&rtems_global_user_env) { +! rtems_user_env_t *tmp = malloc(sizeof(rtems_user_env_t)); +! if (!tmp) + return RTEMS_NO_MEMORY; ++ ++ tmp->refcnt = 1; ++ ++ sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); ++ if (sc != RTEMS_SUCCESSFUL) { ++ /* don't use free_user_env because the pathlocs are ++ * not initialized yet ++ */ ++ free(tmp); ++ return sc; ++ } ++ rtems_current_user_env = tmp; + }; + + *rtems_current_user_env = rtems_global_user_env; /* get the global values*/ + rtems_current_user_env->task_id=task_id; /* mark the local values*/ ++ ++ /* get a clean root */ ++ rtems_filesystem_root = THE_ROOT_FS_LOC; ++ ++ /* Clone the pathlocs. In contrast to most other ++ * code we must _not_ free the original locs because ++ * what we are trying to do here is forking off ++ * clones. ++ */ ++ ++ rtems_filesystem_evaluate_path("/", 0, &loc, 0); ++ rtems_filesystem_root = loc; ++ rtems_filesystem_evaluate_path("/", 0, &loc, 0); ++ rtems_filesystem_current = loc; + + return RTEMS_SUCCESSFUL; + } +*************** +*** 51,56 **** +--- 96,115 ---- + * Task_id (remote) and RTEMS_SELF(current). + */ + ++ /* NOTE: ++ * ++ * THIS CODE HAS NO PROTECTION IMPLEMENTED ++ * ++ * Tasks who wish to share their environments must ++ * ++ * a) assert that no participants are concurrently ++ * executing ++ * libio_share_private_env() and/or libio_set_private_env() ++ * ++ * b) mutex access to rtems_filesystem_current, rtems_filesytem_root ++ * while changing any of those (chdir(), chroot()). ++ */ ++ + rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { + rtems_status_code sc; + rtems_user_env_t * shared_user_env; +*************** +*** 61,81 **** + + if (rtems_current_user_env->task_id==current_task_id) { + /* kill the current user env & task_var*/ +! free(rtems_current_user_env); + sc = rtems_task_variable_delete(RTEMS_SELF,(void*)&rtems_current_user_env); + if (sc != RTEMS_SUCCESSFUL) return sc; + }; + + sc = rtems_task_variable_get(task_id,(void*)&rtems_current_user_env, + (void*)&shared_user_env ); +! if (sc != RTEMS_SUCCESSFUL) return sc; + +! /* don't free(NULL'ed) at the task_delete. It is a shared var... */ +! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,NULL); +! if (sc != RTEMS_SUCCESSFUL) return sc; + + /* the current_user_env is the same pointer that remote env */ + rtems_current_user_env = shared_user_env; + + return RTEMS_SUCCESSFUL; + } +--- 120,152 ---- + + if (rtems_current_user_env->task_id==current_task_id) { + /* kill the current user env & task_var*/ +! rtems_user_env_t *tmp = rtems_current_user_env; + sc = rtems_task_variable_delete(RTEMS_SELF,(void*)&rtems_current_user_env); + if (sc != RTEMS_SUCCESSFUL) return sc; ++ free_user_env(tmp); + }; + ++ /* AT THIS POINT, rtems_current_user_env is DANGLING */ ++ + sc = rtems_task_variable_get(task_id,(void*)&rtems_current_user_env, + (void*)&shared_user_env ); +! if (sc != RTEMS_SUCCESSFUL) +! goto bailout; + +! sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); +! if (sc != RTEMS_SUCCESSFUL) +! goto bailout; + + /* the current_user_env is the same pointer that remote env */ + rtems_current_user_env = shared_user_env; + ++ /* increase the reference count */ ++ rtems_current_user_env->refcnt++; ++ + return RTEMS_SUCCESSFUL; ++ ++ bailout: ++ /* fallback to the global env */ ++ rtems_current_user_env = &rtems_global_user_env; ++ return sc; + } diff --git a/rtemsNfs/src/Makefile b/rtemsNfs/src/Makefile new file mode 100644 index 0000000..431b5ad --- /dev/null +++ b/rtemsNfs/src/Makefile @@ -0,0 +1,104 @@ +# +# $Id$ +# +# Templates/Makefile.leaf +# Template leaf node Makefile +# + +# if you have CEXP set this variable to 'YES' +# and some "help" info will be compiled in. +HAVE_CEXP=YES + +# C source names, if any, go here -- minus the .c +C_PIECES_YES=rpcio nfs sock_mbuf xdr_mbuf dirutils rpcio.modini nfs.modini cexphelp +C_PIECES_NO=rpcio nfs sock_mbuf xdr_mbuf + +C_PIECES=$(C_PIECES_$(HAVE_CEXP)) + +C_FILES=$(C_PIECES:%=%.c) +C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) + +# C++ source names, if any, go here -- minus the .cc +CC_PIECES= +CC_FILES=$(CC_PIECES:%=%.cc) +CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o) + +H_FILES=librtemsNfs.h rpcio.h +INST_HEADERS=librtemsNfs.h + +# Assembly source names, if any, go here -- minus the .S +S_PIECES= +S_FILES=$(S_PIECES:%=%.S) +S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o) + +SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) +OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES) $(wildcard ../proto/$(ARCH)/*.o) + +PGMS=${ARCH}/nfs.obj ${ARCH}/rpcio.obj ${ARCH}/dirutils.obj + +LIBNAME=librtemsNfs.a + +LIB=$(ARCH)/$(LIBNAME) + +include $(RTEMS_MAKEFILE_PATH)/Makefile.inc +include $(RTEMS_CUSTOM) +include $(RTEMS_ROOT)/make/lib.cfg + +# +# (OPTIONAL) Add local stuff here using += +# + +DEFS_CEXP_YES=-DHAVE_CEXP + +DEFINES += $(DEFS_CEXP_$(HAVE_CEXP)) + +CPPFLAGS += -I. -I../proto + +CFLAGS += + +# +# CFLAGS_DEBUG_V are used when the `make debug' target is built. +# To link your application with the non-optimized RTEMS routines, +# uncomment the following line: +# CFLAGS_DEBUG_V += -qrtems_debug +# + +LDFLAGS += + +# +# Add your list of files to delete here. The config files +# already know how to delete some stuff, so you may want +# to just run 'make clean' first to see what gets missed. +# 'make clobber' already includes 'make clean' +# + +#CLEAN_ADDITIONS += xxx-your-debris-goes-here +CLOBBER_ADDITIONS += + +ifndef RTEMS_SITE_INSTALLDIR +RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE) +endif + +%nfs.obj: %nfs.o %nfs.modini.o + $(LD) -r -o $@ $^ -L../proto/$(ARCH) -lnfsprot + +%rpcio.obj: %rpcio.o %sock_mbuf.o %xdr_mbuf.o %rpcio.modini.o + $(LD) -r -o $@ $^ + +%dirutils.obj: %dirutils.o + $(LD) -r -o $@ $^ + +$(LIB): $(OBJS) + $(make-library) + +all: ${ARCH} $(SRCS) $(PGMS) $(LIB) + +tar: + echo not implemented + +# Install the program(s), appending _g or _p as appropriate. +# for include files, just use $(INSTALL_CHANGE) +install: all + $(INSTALL_VARIANT) -m 555 ${PGMS} ${RTEMS_SITE_INSTALLDIR}/bin + $(INSTALL_VARIANT) -m 555 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib + $(INSTALL_CHANGE) -m 444 ${INST_HEADERS} ${RTEMS_SITE_INSTALLDIR}/include diff --git a/rtemsNfs/src/cexphelp.c b/rtemsNfs/src/cexphelp.c new file mode 100644 index 0000000..d062ed1 --- /dev/null +++ b/rtemsNfs/src/cexphelp.c @@ -0,0 +1,16 @@ +#include +#include +CEXP_HELP_TAB_BEGIN(rtemsNfs) + HELP( +"Mount a remote filesystem (NFS). The mount point (must not be a NFS dir)\n" +"is created on the fly if not existing already.\n" +"uid/gid to use may be specified:\n" +" hostspec: [uid.gid@]hostname_or_ipaddr\n" + , int, nfsMount, (char *hostspec, char *exportdir, char *mntpoint) + ), + HELP( +"Print all currently mounted NFS directories to open file handle.\n" +"Pass f = 0 to print to stdout\n" + , int, nfsMountsShow, (FILE *f) + ), +CEXP_HELP_TAB_END diff --git a/rtemsNfs/src/dirutils.c b/rtemsNfs/src/dirutils.c new file mode 100644 index 0000000..91b1858 --- /dev/null +++ b/rtemsNfs/src/dirutils.c @@ -0,0 +1,323 @@ +/* $Id$ */ + +/* very crude and basic fs utilities for testing the NFS */ + +/* Till Straumann, , 10/2002 */ + +/* + * Copyright 2002, Stanford University and + * Till Straumann + * + * Stanford Notice + * *************** + * + * Acknowledgement of sponsorship + * * * * * * * * * * * * * * * * * + * This software was produced by the Stanford Linear Accelerator Center, + * Stanford University, under Contract DE-AC03-76SFO0515 with the Department + * of Energy. + * + * Government disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, + * or assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately + * owned rights. + * + * Stanford disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * This product is subject to the EPICS open license + * - - - - - - - - - - - - - - - - - - - - - - - - - + * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php + * for more information. + * + * Maintenance of notice + * - - - - - - - - - - - + * In the interest of clarity regarding the origin and status of this + * software, Stanford University requests that any recipient of it maintain + * this notice affixed to any distribution by the recipient that contains a + * copy or derivative of this software. + */ + +#ifdef __vxworks +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CEXP +#include +#endif + +#define BUFFERSZ 10000 + +#ifndef __vxworks +int +pwd(void) +{ +char buf[MAXPATHLEN]; + + if ( !getcwd(buf,MAXPATHLEN)) { + perror("getcwd"); + return -1; + } else { + printf("%s\n",buf); + } + return 0; +} + +static int +ls_r(char *path, char *chpt, char *name, struct stat *buf) +{ +char *t; + sprintf(chpt, "/%s", name); + if (lstat(path,buf)) { + fprintf(stderr,"stat(%s): %s\n", path, strerror(errno)); + return -1; + } + switch ( buf->st_mode & S_IFMT ) { + case S_IFSOCK: + case S_IFIFO: t = "|"; break; + + default: + case S_IFREG: + case S_IFBLK: + case S_IFCHR: + t = ""; break; + case S_IFDIR: + t = "/"; break; + case S_IFLNK: + t = "@"; break; + } + + printf("%10li, %10lib, %5i.%-5i 0%04o %s%s\n", + buf->st_ino, + buf->st_size, + buf->st_uid, + buf->st_gid, + buf->st_mode & ~S_IFMT, + name, + t); + *chpt = 0; + return 0; +} + +int +ls(char *dir, char *opts) +{ +struct dirent *de; +char path[MAXPATHLEN+1]; +char *chpt; +DIR *dp = 0; +int rval = -1; +struct stat buf; + + if ( !dir ) + dir = "."; + + strncpy(path, dir, MAXPATHLEN); + path[MAXPATHLEN] = 0; + chpt = path+strlen(path); + + if ( !(dp=opendir(dir)) ) { + perror("opendir"); + goto cleanup; + } + + while ( (de = readdir(dp)) ) { + ls_r(path, chpt, de->d_name, &buf); + } + + rval = 0; + +cleanup: + if (dp) + closedir(dp); + return rval; +} +#endif + +#if 0 + fprintf(stderr, "usage: cp(""from"",[""to""[,""-f""]]\n"); + fprintf(stderr, " ""to""==NULL -> stdout\n"); + fprintf(stderr, " ""-f"" -> overwrite existing file\n"); +#endif + +int +cp(char *from, char *to, char *opts) +{ +struct stat st; +int got,put,tot; +char *buf = 0; +int rval = -1; +int ffd = -1; +int tfd = -1; +int flags = O_CREAT | O_WRONLY | O_TRUNC | O_EXCL; + + if (from) { + + if ((ffd=open(from,O_RDONLY,0)) < 0) { + fprintf(stderr, + "Opening %s for reading: %s\n", + from, + strerror(errno)); + goto cleanup; + } + + if (fstat(ffd, &st)) { + fprintf(stderr, + "rstat(%s): %s\n", + from, + strerror(errno)); + goto cleanup; + } + + + if (!S_ISREG(st.st_mode)) { + fprintf(stderr,"Refuse to copy a non-regular file\n"); + errno = EINVAL; + goto cleanup; + } + + } else { + ffd = fileno(stdin); + st.st_mode = 0644; + } + + if (opts && strchr(opts,'f')) + flags &= ~ O_EXCL; + + if (to) { + if ((tfd=open(to,flags,st.st_mode)) < 0) { + fprintf(stderr, + "Opening %s for writing: %s\n", + to, + strerror(errno)); + goto cleanup; + } + } else { + tfd = fileno(stdout); + } + + if ( !(buf = malloc(BUFFERSZ)) ) { + fprintf(stderr,"cp: unable to allocate buffer - out of memory\n"); + errno = ENOMEM; + goto cleanup; + } + + tot = 0; + while ( (got=read(ffd,buf,BUFFERSZ)) > 0 ) { + if (got !=(put=write(tfd,buf,got))) { + if (put<0) { + fprintf(stderr,"Write error: %s\n",strerror(errno)); + } else { + fprintf(stderr,"Write error: unable to write whole block\n"); + } + goto cleanup; + } + tot += got; + } + if (got < 0) { + fprintf(stderr,"Read error: %s\n",strerror(errno)); + goto cleanup; + } + rval = 0; + +cleanup: + free(buf); + + if (from && ffd>=0) + close(ffd); + if (to && tfd>=0) + close(tfd); + + return rval; +} + +int +ln(char *to, char *name, char *opts) +{ + if (!to) { + fprintf(stderr,"ln: need 'to' argument\n"); + return -1; + } + if (!name) { + if ( !(name = strrchr(to,'/')) ) { + fprintf(stderr, + "ln: 'unable to link %s to %s\n", + to,to); + return -1; + } + name++; + } + if (opts || strchr(opts,'s')) { + if (symlink(name,to)) { + fprintf(stderr,"symlink: %s\n",strerror(errno)); + return -1; + } + } else { + if (link(name,to)) { + fprintf(stderr,"hardlink: %s\n",strerror(errno)); + return -1; + } + } + return 0; +} + +int +rm(char *path) +{ + return unlink(path); +} + +int +cd(char *path) +{ + return chdir(path); +} + +#ifdef HAVE_CEXP +static CexpHelpTabRec _cexpHelpTabDirutils[]={ + HELP( +"copy a file: cp(""from"",[""to""[,""-f""]])\n\ + from = NULL <-- stdin\n\ + to = NULL --> stdout\n\ + option -f: overwrite existing file\n", + int, + cp, (char *from, char *to, char *options) + ), + HELP( +"list a directory: ls([""dir""])\n", + int, + ls, (char *dir) + ), + HELP( +"remove a file\n", + int, + rm, (char *path) + ), + HELP( +"change the working directory\n", + int, + cd, (char *path) + ), + HELP( +"create a link: ln(""to"",""name"",""[-s]""\n\ + -s creates a symlink\n", + int, + ln, (char *to, char *name, char *options) + ), + HELP("",,0,) +}; +#endif diff --git a/rtemsNfs/src/librtemsNfs.h b/rtemsNfs/src/librtemsNfs.h new file mode 100644 index 0000000..880842c --- /dev/null +++ b/rtemsNfs/src/librtemsNfs.h @@ -0,0 +1,158 @@ +#ifndef LIB_RTEMS_NFS_CLIENT_H +#define LIB_RTEMS_NFS_CLIENT_H +/* $Id$ */ + +/* public interface to the NFS client library for RTEMS */ + +/* Author: Till Straumann 2002-2003 */ + +/* + * Copyright 2002-2003, Stanford University and + * Till Straumann + * + * Stanford Notice + * *************** + * + * Acknowledgement of sponsorship + * * * * * * * * * * * * * * * * * + * This software was produced by the Stanford Linear Accelerator Center, + * Stanford University, under Contract DE-AC03-76SFO0515 with the Department + * of Energy. + * + * Government disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, + * or assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately + * owned rights. + * + * Stanford disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * This product is subject to the EPICS open license + * - - - - - - - - - - - - - - - - - - - - - - - - - + * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php + * for more information. + * + * Maintenance of notice + * - - - - - - - - - - - + * In the interest of clarity regarding the origin and status of this + * software, Stanford University requests that any recipient of it maintain + * this notice affixed to any distribution by the recipient that contains a + * copy or derivative of this software. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef HAVE_CEXP_H +#include +#endif + +/* RPCIO driver interface. + * If you need RPCIO for other purposes than NFS + * you may want to include +#include "rpcio.h" + */ + +/* Initialize the driver + * + * RETURNS: 0 on success, -1 on failure + */ +int +rpcUdpInit(void); + +/* Cleanup/Stop + * + * RETURNS: 0 on success, nonzero if still in use + */ +int +rpcUdpCleanup(void); + +/* NFS driver interface */ + +/* Initialize the NFS driver. + * + * NOTE: The RPCIO driver must have been initialized prior to + * calling this. + * + * ARGS: depth of the small and big + * transaction pools, i.e. how + * many transactions (buffers) + * should always be kept around. + * + * (If more transactions are needed, + * they are created and destroyed + * on the fly). + * + * Supply zero values to have the + * driver chose reasonable defaults. + */ +int +nfsInit(int smallPoolDepth, int bigPoolDepth); + +/* Driver cleanup code + * + * RETURNS: 0 on success, nonzero if still in use + */ +int +nfsCleanup(void); + +/* Dump a list of the currently mounted NFS to a file + * (stdout is used in case f==NULL) + */ +int +nfsMountsShow(FILE *f); + +/* convenience wrapper + * + * NOTE: this routine calls NON-REENTRANT + * gethostbyname() if the host is + * not in 'dot' notation. + */ +int +nfsMount(char *uidhost, char *path, char *mntpoint); + +/* Alternatively, a pointer to the filesystem operations + * table can be supplied to the native RTEMS (NON-POSIX!) + * 'mount()' call. + * Supply a ":" string + * for 'device' argument to 'mount()'. + */ +extern struct _rtems_filesystem_operations_table nfs_fs_ops; + +/* A utility routine to find the path leading to a + * rtems_filesystem_location_info_t node. + * + * This should really be present in libcsupport... + * + * INPUT: 'loc' and a buffer 'buf' (length 'len') to hold the + * path. + * OUTPUT: path copied into 'buf' + * + * RETURNS: 0 on success, RTEMS error code on error. + */ +rtems_status_code +rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc); +#endif diff --git a/rtemsNfs/src/nfs.c b/rtemsNfs/src/nfs.c new file mode 100644 index 0000000..73f4354 --- /dev/null +++ b/rtemsNfs/src/nfs.c @@ -0,0 +1,3317 @@ +/* nfs.c,v 1.33 2004/09/22 22:10:41 till Exp */ + +/* NFS client implementation for RTEMS; hooks into the RTEMS filesystem */ + +/* Author: Till Straumann 2002 */ + +/* + * Copyright 2002, Stanford University and + * Till Straumann + * + * Stanford Notice + * *************** + * + * Acknowledgement of sponsorship + * * * * * * * * * * * * * * * * * + * This software was produced by the Stanford Linear Accelerator Center, + * Stanford University, under Contract DE-AC03-76SFO0515 with the Department + * of Energy. + * + * Government disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, + * or assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately + * owned rights. + * + * Stanford disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * This product is subject to the EPICS open license + * - - - - - - - - - - - - - - - - - - - - - - - - - + * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php + * for more information. + * + * Maintenance of notice + * - - - - - - - - - - - + * In the interest of clarity regarding the origin and status of this + * software, Stanford University requests that any recipient of it maintain + * this notice affixed to any distribution by the recipient that contains a + * copy or derivative of this software. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include "rpcio.h" + +#ifdef HAVE_CEXP_H +#include +#endif + + +/* Configurable parameters */ + +/* Estimated average length of a filename (including terminating 0). + * This was calculated by doing + * + * find -print -exec basename '{}' \; > feil + * wc feil + * + * AVG_NAMLEN = (num_chars + num_lines)/num_lines + */ +#define CONFIG_AVG_NAMLEN 10 + +#define CONFIG_NFS_SMALL_XACT_SIZE 800 /* size of RPC arguments for non-write ops */ +/* lifetime of NFS attributes in a NfsNode; + * the time is in seconds and the lifetime is + * infinite if the symbol is #undef + */ +#define CONFIG_ATTR_LIFETIME 10/*secs*/ + +/* dont change this without changing the maximal write size */ +#define CONFIG_NFS_BIG_XACT_SIZE UDPMSGSIZE /* dont change this */ + +/* The real values for these are specified further down */ +#define NFSCALL_TIMEOUT (&_nfscalltimeout) +#define MNTCALL_TIMEOUT (&_nfscalltimeout) +static struct timeval _nfscalltimeout = { 10, 0 }; /* {secs, us } */ + +/* More or less fixed constants; in particular, NFS3 is not supported */ +#define DELIM '/' +#define HOSTDELIM ':' +#define UPDIR ".." +#define UIDSEP '@' +#define NFS_VERSION_2 NFS_VERSION + +/* we use a dynamically assigned major number */ +#define NFS_MAJOR (nfsGlob.nfs_major) + + +/* NOTE: RTEMS (ss-20020301) uses a 'short st_ino' type :-( but the + * NFS fileid is 32 bit. + * As a workarount, we merge the upper 16bits of the fileid into the + * minor device no. Hence, it is still possible to uniquely identify + * a file by looking at its device number (major = nfs, minor = part + * of the fileid + our 'nfs-id' identifier). + * + * This has an impact on performance, as e.g. getcwd() stats() all + * directory entries when it believes it has crossed a mount point + * (a.st_dev != b.st_dev). + * + * OTOH, it also might cause node comparison failure! E.g. 'getcwd()' + * assumes that two nodes residing in the same directory must be located + * on the same device and hence compares 'st_ino' only. + * If two files in the same directory have the same inode number + * modulo 2^16, they will be considered equal (although their device + * number doesn't match - getcwd doesn't look at it). + * + * Other software might or might not be affected. + * + * The only clean solution to this problem is bumping up the size of + * 'ino_t' at least to 'long'. + * Note that this requires _all_ software (libraries etc.) to be + * recompiled. + */ + +#define NFS_MAKE_DEV_T_INO_HACK(node) \ + rtems_filesystem_make_dev_t( NFS_MAJOR, \ + (((node)->nfs->id)<<16) | (SERP_ATTR((node)).fileid >> 16) ) + +/* use our 'nfs id' and the server's fsid for the minor device number + * this should be fairly unique + */ +#define NFS_MAKE_DEV_T(node) \ + rtems_filesystem_make_dev_t( NFS_MAJOR, \ + (((node)->nfs->id)<<16) | (SERP_ATTR((node)).fsid & ((1<<16)-1)) ) + +#define DIRENT_HEADER_SIZE ( sizeof(struct dirent) - \ + sizeof( ((struct dirent *)0)->d_name ) ) + + +/* debugging flags */ +#define DEBUG_COUNT_NODES (1<<0) +#define DEBUG_TRACK_NODES (1<<1) +#define DEBUG_EVALPATH (1<<2) +#define DEBUG_READDIR (1<<3) +#define DEBUG_SYSCALLS (1<<4) + +/* #define DEBUG ( DEBUG_SYSCALLS | DEBUG_COUNT_NODES ) */ + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +#define MUTEX_ATTRIBUTES (RTEMS_LOCAL | \ + RTEMS_PRIORITY | \ + RTEMS_INHERIT_PRIORITY | \ + RTEMS_BINARY_SEMAPHORE) + +#define LOCK(s) do { rtems_semaphore_obtain((s), \ + RTEMS_WAIT, \ + RTEMS_NO_TIMEOUT); \ + } while (0) + +#define UNLOCK(s) do { rtems_semaphore_release((s)); \ + } while (0) + +/***************************************** + Types with Associated XDR Routines + *****************************************/ + +/* a string buffer with a maximal length. + * If the buffer pointer is NULL, it is updated + * with an appropriately allocated area. + */ +typedef struct strbuf { + char *buf; + u_int max; +} strbuf; + +static bool_t +xdr_strbuf(XDR *xdrs, strbuf *obj) +{ + return xdr_string(xdrs, &obj->buf, obj->max); +} + +/* Read 'readlink' results into a 'strbuf'. + * This is convenient as it avoids + * one extra step of copying / lenght + * checking. + */ +typedef struct readlinkres_strbuf { + nfsstat status; + strbuf strbuf; +} readlinkres_strbuf; + +static bool_t +xdr_readlinkres_strbuf(XDR *xdrs, readlinkres_strbuf *objp) +{ + if ( !xdr_nfsstat(xdrs, &objp->status) ) + return FALSE; + + if ( NFS_OK == objp->status ) { + if ( !xdr_string(xdrs, &objp->strbuf.buf, objp->strbuf.max) ) + return FALSE; + } + return TRUE; +} + + +/* DirInfoRec is used instead of dirresargs + * to convert recursion into iteration. The + * 'rpcgen'erated xdr_dirresargs ends up + * doing nested calls when unpacking the + * 'next' pointers. + */ + +typedef struct DirInfoRec_ { + readdirargs readdirargs; + /* clone of the 'readdirres' fields; + * the cookie is put into the readdirargs above + */ + nfsstat status; + char *buf, *ptr; + int len; + bool_t eofreached; +} DirInfoRec, *DirInfo; + +/* this deals with one entry / record */ +static bool_t +xdr_dir_info_entry(XDR *xdrs, DirInfo di) +{ +union { + char nambuf[NFS_MAXNAMLEN+1]; + nfscookie cookie; +} dummy; +struct dirent *pde = (struct dirent *)di->ptr; +u_int fileid; +char *name; +register int nlen = 0,len,naligned = 0; +nfscookie *pcookie; + + len = di->len; + + if ( !xdr_u_int(xdrs, &fileid) ) + return FALSE; + + /* we must pass the address of a char* */ + name = (len > NFS_MAXNAMLEN) ? pde->d_name : dummy.nambuf; + + if ( !xdr_filename(xdrs, &name) ) { + return FALSE; + } + + if (len >= 0) { + nlen = strlen(name); + naligned = nlen + 1 /* string delimiter */ + 3 /* alignment */; + naligned &= ~3; + len -= naligned; + } + + /* if the cookie goes into the DirInfo, we hope this doesn't fail + * - the caller ends up with an invalid readdirargs cookie otherwise... + */ + pcookie = (len >= 0) ? &di->readdirargs.cookie : &dummy.cookie; + if ( !xdr_nfscookie(xdrs, pcookie) ) { + return FALSE; + } + + di->len = len; + /* adjust the buffer pointer */ + if (len >= 0) { + pde->d_ino = fileid; + pde->d_namlen = nlen; + pde->d_off = di->ptr - di->buf; + if (name == dummy.nambuf) { + memcpy(pde->d_name, dummy.nambuf, nlen + 1); + } + pde->d_reclen = DIRENT_HEADER_SIZE + naligned; + di->ptr += pde->d_reclen; + } + + return TRUE; +} + +/* this routine loops over all entries */ +static bool_t +xdr_dir_info(XDR *xdrs, DirInfo di) +{ +DirInfo dip; + + if ( !xdr_nfsstat(xdrs, &di->status) ) + return FALSE; + + if ( NFS_OK != di->status ) + return TRUE; + + dip = di; + + while (dip) { + /* reserve space for the dirent 'header' - we assume it's word aligned! */ +#ifdef DEBUG + assert( DIRENT_HEADER_SIZE % 4 == 0 ); +#endif + dip->len -= DIRENT_HEADER_SIZE; + + /* we pass a 0 size - size is unused since + * we always pass a non-NULL pointer + */ + if ( !xdr_pointer(xdrs, (caddr_t*)&dip, 0 /* size */, xdr_dir_info_entry) ) + return FALSE; + } + + if ( ! xdr_bool(xdrs, &di->eofreached) ) + return FALSE; + + /* if everything fits into the XDR buffer but not the user's buffer, + * they must resume reading from where xdr_dir_info_entry() started + * skipping and 'eofreached' needs to be adjusted + */ + if ( di->len < 0 && di->eofreached ) + di->eofreached = FALSE; + + return TRUE; +} + + +/* a type better suited for node operations + * than diropres. + * fattr and fhs are swapped so parts of this + * structure may be used as a diroparg which + * is practical when looking up paths. + */ + +/* Macro for accessing serporid fields + */ +#define SERP_ARGS(node) ((node)->serporid.serporid_u.serporid.arg_u) +#define SERP_ATTR(node) ((node)->serporid.serporid_u.serporid.attributes) +#define SERP_FILE(node) ((node)->serporid.serporid_u.serporid.file) + + +typedef struct serporidok { + fattr attributes; + nfs_fh file; + union { + struct { + filename name; + } diroparg; + struct { + sattr attributes; + } sattrarg; + struct { + u_int offset; + u_int count; + u_int totalcount; + } readarg; + struct { + u_int beginoffset; + u_int offset; + u_int totalcount; + struct { + u_int data_len; + char* data_val; + } data; + } writearg; + struct { + filename name; + sattr attributes; + } createarg; + struct { + filename name; + diropargs to; + } renamearg; + struct { + diropargs to; + } linkarg; + struct { + filename name; + nfspath to; + sattr attributes; + } symlinkarg; + struct { + nfscookie cookie; + u_int count; + } readdirarg; + } arg_u; +} serporidok; + +typedef struct serporid { + nfsstat status; + union { + serporidok serporid; + } serporid_u; +} serporid; + +/* an XDR routine to encode/decode the inverted diropres + * into an nfsnodestat; + * + * NOTE: this routine only acts on + * - 'serporid.status' + * - 'serporid.file' + * - 'serporid.attributes' + * and leaves the 'arg_u' alone. + * + * The idea is that a 'diropres' is read into 'serporid' + * which can then be used as an argument to subsequent + * NFS-RPCs (after filling in the node's arg_u). + */ +static bool_t +xdr_serporidok(XDR *xdrs, serporidok *objp) +{ + if (!xdr_nfs_fh (xdrs, &objp->file)) + return FALSE; + if (!xdr_fattr (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +static bool_t +xdr_serporid(XDR *xdrs, serporid *objp) +{ + if (!xdr_nfsstat (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS_OK: + if (!xdr_serporidok(xdrs, &objp->serporid_u.serporid)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +/***************************************** + Data Structures and Types + *****************************************/ + +/* 'time()' hack with less overhead; */ + +/* assume reading a long word is atomic */ +#define READ_LONG_IS_ATOMIC + +typedef rtems_unsigned32 TimeStamp; + +static inline TimeStamp +nowSeconds(void) +{ +register rtems_unsigned32 rval; +#ifndef READ_LONG_IS_ATOMIC +rtems_interrupt_level l; + + rtems_interrupt_disable(level); +#endif + + rval = _TOD_Seconds_since_epoch; + +#ifndef READ_LONG_IS_ATOMIC + rtems_interrupt_enable(level); +#endif + return rval; +} + + +/* Per mounted FS structure */ +typedef struct NfsRec_ { + /* the NFS server we're talking to. + */ + RpcUdpServer server; + /* statistics; how many NfsNodes are + * currently alive. + */ + int nodesInUse; +#if DEBUG & DEBUG_COUNT_NODES + /* statistics; how many 'NfsNode.str' + * strings are currently allocated. + */ + int stringsInUse; +#endif + /* A small number who uniquely + * identifies a mounted NFS within + * this driver (i.e. this NfsRec). + * Each time a NFS is mounted, the + * global ID counter is incremented + * and its value is assigned to the + * newly created NfsRec. + */ + u_short id; + /* Our RTEMS filesystem mt_entry + */ + rtems_filesystem_mount_table_entry_t *mt_entry; + /* Next NfsRec on a linked list who + * is anchored at nfsGlob + */ + struct NfsRec_ *next; + /* Who we pretend we are + */ + u_long uid,gid; +} NfsRec, *Nfs; + +typedef struct NfsNodeRec_ { + /* This holds this node's attributes + * (stats) and its nfs filehandle. + * It also contains room for nfs rpc + * arguments. + */ + serporid serporid; + /* The arguments we used when doing + * the 'lookup' call for this node. + * We need this information (especially + * the directory FH) for performing + * certain operations on this + * node (in particular: for unlinking + * it from a parent directory) + */ + diropargs args; + /* FS this node belongs to + */ + Nfs nfs; + /* A buffer for the string the + * args.name points to. + * We need this because args.name might + * temporarily point to strings on the + * stack. Duplicates are allocated from + * the heap and attached to 'str' so + * they can be released as appropriate. + */ + char *str; + /* A timestamp for the stats + */ + TimeStamp age; +} NfsNodeRec, *NfsNode; + +/***************************************** + Forward Declarations + *****************************************/ + +static int nfs_readlink( + rtems_filesystem_location_info_t *loc, /* IN */ + char *buf, /* OUT */ + size_t len +); + +static int updateAttr(NfsNode node, int force); + +/* Mask bits when setting attributes. + * Only the 'arg' fields with their + * corresponding bit set in the mask + * will be used. The others are left + * unchanged. + * The 'TOUCH' bits instruct nfs_sattr() + * to update the respective time + * fields to the current time + */ +#define SATTR_MODE (1<<0) +#define SATTR_UID (1<<1) +#define SATTR_GID (1<<2) +#define SATTR_SIZE (1<<3) +#define SATTR_ATIME (1<<4) +#define SATTR_TOUCHA (1<<5) +#define SATTR_MTIME (1<<6) +#define SATTR_TOUCHM (1<<7) +#define SATTR_TOUCH (SATTR_TOUCHM | SATTR_TOUCHA) + +static int +nfs_sattr(NfsNode node, sattr *arg, u_long mask); + +extern struct _rtems_filesystem_operations_table nfs_fs_ops; +extern struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers; +extern struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers; +extern struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers; +extern rtems_driver_address_table drvNfs; + +int +nfsMountsShow(FILE*); + +rtems_status_code +rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc); + + +/***************************************** + Inline Routines + *****************************************/ + + +/* * * * * * * * * * * * * * * * * * + Trivial Operations on a NfsNode + * * * * * * * * * * * * * * * * * */ + +/* determine if a location 'l' is an NFS root node */ +static inline int +locIsRoot(rtems_filesystem_location_info_t *l) +{ +NfsNode me = (NfsNode) l->node_access; +NfsNode r; + r = (NfsNode)l->mt_entry->mt_fs_root.node_access; + return SERP_ATTR(r).fileid == SERP_ATTR(me).fileid && + SERP_ATTR(r).fsid == SERP_ATTR(me).fsid; +} + +/* determine if a location 'l' is an NFS node */ +static inline int +locIsNfs(rtems_filesystem_location_info_t *l) +{ + return l->ops == &nfs_fs_ops; +} + +/* determine if two locations refer to the + * same entity. We know that 'nfsloc' is a + * location inside nfs. However, we needn't + * know anything about 'anyloc'. + */ +static inline int +locAreEqual( + rtems_filesystem_location_info_t *nfsloc, + rtems_filesystem_location_info_t *anyloc +) +{ +NfsNode na = (NfsNode) nfsloc->node_access; +NfsNode nb; + + if (!locIsNfs(anyloc)) + return 0; + + nb = (NfsNode) anyloc->node_access; + + if (na->nfs != nb->nfs) + return 0; + + updateAttr(nb, 0); + + return SERP_ATTR(na).fileid == SERP_ATTR(nb).fileid && + SERP_ATTR(na).fsid == SERP_ATTR(nb).fsid; +} + + + +/***************************************** + Global Variables + *****************************************/ + +/* These are (except for MAXNAMLEN/MAXPATHLEN) copied from IMFS */ + +static rtems_filesystem_limits_and_options_t +nfs_limits_and_options = { + 5, /* link_max */ + 6, /* max_canon */ + 7, /* max_input */ + NFS_MAXNAMLEN, /* name_max */ + NFS_MAXPATHLEN, /* path_max */ + 2, /* pipe_buf */ + 1, /* posix_async_io */ + 2, /* posix_chown_restrictions */ + 3, /* posix_no_trunc */ + 4, /* posix_prio_io */ + 5, /* posix_sync_io */ + 6 /* posix_vdisable */ +}; + +/* size of an encoded 'entry' object */ +static int dirres_entry_size; + +/* Global stuff and statistics */ +static struct nfsstats { + /* A lock for protecting the + * linked ist of mounted NFS + * and the num_mounted_fs field + */ + rtems_id llock; + /* A lock for protecting misc + * stuff within the driver. + * The lock must only be held + * for short periods of time. + */ + rtems_id lock; + /* Our major number as assigned + * by RTEMS + */ + rtems_device_major_number nfs_major; + /* The number of currently + * mounted NFS + */ + int num_mounted_fs; + /* A list of the currently + * mounted NFS + */ + struct NfsRec_ *mounted_fs; + /* A counter for allocating + * unique IDs to each mounted + * NFS. + * Assume we are not going to + * do more than 16k mounts + * during the system lifetime + */ + u_short fs_ids; +} nfsGlob = {0/* IMPORTANT */}; + + +/* Two pools of RPC transactions; + * One with small send buffers + * the other with a big one. + * The actual size of the small + * buffer is configurable (see top). + * + * Note: The RX buffers are always + * big + */ +static RpcUdpXactPool smallPool = 0; +static RpcUdpXactPool bigPool = 0; + + +/***************************************** + Implementation + *****************************************/ + +/* Create a Nfs object. This is + * per-mounted NFS information. + * + * ARGS: The Nfs server handle. + * + * RETURNS: Nfs on success, + * NULL on failure with + * errno set + * + * NOTE: The submitted server + * object is 'owned' by + * this Nfs and will be + * destroyed by nfsDestroy() + */ +static Nfs +nfsCreate(RpcUdpServer server) +{ +Nfs rval = calloc(1,sizeof(*rval)); + + if (rval) { + rval->server = server; + LOCK(nfsGlob.llock); + rval->next = nfsGlob.mounted_fs; + nfsGlob.mounted_fs = rval; + UNLOCK(nfsGlob.llock); + } else { + errno = ENOMEM; + } + return rval; +} + +/* Destroy an Nfs object and + * its associated server + */ +static void +nfsDestroy(Nfs nfs) +{ +register Nfs prev; + if (!nfs) + return; + + LOCK(nfsGlob.llock); + if (nfs == nfsGlob.mounted_fs) + nfsGlob.mounted_fs = nfs->next; + else { + for (prev = nfsGlob.mounted_fs; + prev && prev->next != nfs; + prev = prev->next) + /* nothing else to do */; + assert( prev ); + prev->next = nfs->next; + } + UNLOCK(nfsGlob.llock); + + nfs->next = 0; /* paranoia */ + rpcUdpServerDestroy(nfs->server); + free(nfs); +} + +/* + * Create a Node. The node will + * be associated with a particular + * mounted NFS identified by 'nfs' + * Optionally, a NFS file handle + * may be copied into this node. + * + * ARGS: nfs of the NFS this node + * belongs to. + * NFS file handle identifying + * this node. + * RETURNS: node on success, + * NULL on failure with errno + * set. + * + * NOTE: The caller of this routine + * is responsible for copying + * a NFS file handle if she + * choses to pass a NULL fh. + * + * The driver code assumes the + * a node always has a valid + * NFS filehandle and file + * attributes (unless the latter + * are aged). + */ +static NfsNode +nfsNodeCreate(Nfs nfs, nfs_fh *fh) +{ +NfsNode rval = malloc(sizeof(*rval)); + +#if DEBUG & DEBUG_TRACK_NODES + fprintf(stderr,"NFS: creating a node\n"); +#endif + + if (rval) { + if (fh) + memcpy( &SERP_FILE(rval), fh, sizeof(*fh) ); + rval->nfs = nfs; + rval->str = 0; + LOCK(nfsGlob.lock); + nfs->nodesInUse++; + UNLOCK(nfsGlob.lock); + } else { + errno = ENOMEM; + } + + return rval; +} + +/* destroy a node */ +static void +nfsNodeDestroy(NfsNode node) +{ +#if DEBUG & DEBUG_TRACK_NODES + fprintf(stderr,"NFS: destroying a node\n"); +#endif +#if 0 + if (!node) + return; + /* this probably does nothing... */ + xdr_free(xdr_serporid, &node->serporid); +#endif + + LOCK(nfsGlob.lock); + node->nfs->nodesInUse--; +#if DEBUG & DEBUG_COUNT_NODES + if (node->str) + node->nfs->stringsInUse--; +#endif + UNLOCK(nfsGlob.lock); + + if (node->str) + free(node->str); + + free(node); +} + +/* Clone a given node (AKA copy constructor), + * i.e. create an exact copy. + * + * ARGS: node to clone + * RETURNS: new node on success + * NULL on failure with errno set. + * + * NOTE: a string attached to 'str' + * is cloned as well. Outdated + * attributes (of the new copy + * only) will be refreshed + * (if unsuccessful, this could + * be a reason for failure to + * clone a node). + */ +static NfsNode +nfsNodeClone(NfsNode node) +{ +NfsNode rval = nfsNodeCreate(node->nfs, 0); + + if (rval) { + *rval = *node; + + /* must clone the string also */ + if (node->str) { + rval->args.name = rval->str = strdup(node->str); + if (!rval->str) { + nfsNodeDestroy(rval); + return 0; + } +#if DEBUG & DEBUG_COUNT_NODES + LOCK(nfsGlob.lock); + node->nfs->stringsInUse++; + UNLOCK(nfsGlob.lock); +#endif + } + + /* possibly update the stats */ + if (updateAttr(rval, 0 /* only if necessary */)) { + nfsNodeDestroy(rval); + return 0; + } + } + return rval; +} + +/* Initialize the driver. + * + * ARGS: depth of the small and big + * transaction pools, i.e. how + * many transactions (buffers) + * should always be kept around. + * + * (If more transactions are needed, + * they are created and destroyed + * on the fly). + */ +void +nfsInit(int smallPoolDepth, int bigPoolDepth) +{ +entry dummy; + + fprintf(stderr,"This is RTEMS-NFS Release SSRL_RTEMS_20041202\n"); + fprintf(stderr,"(nfs.c,v 1.33 2004/09/22 22:10:41 till Exp)\n\n"); + fprintf(stderr,"Till Straumann, Stanford/SLAC/SSRL 2002\n"); + fprintf(stderr,"See LICENSE file for licensing info\n"); + + /* Get a major number */ + + if (RTEMS_SUCCESSFUL != rtems_io_register_driver(0, &drvNfs, &nfsGlob.nfs_major)) { + fprintf(stderr,"Registering NFS driver failed - %s\n", strerror(errno)); + return; + } + + if (0==smallPoolDepth) + smallPoolDepth = 20; + if (0==bigPoolDepth) + bigPoolDepth = 10; + + /* it's crucial to zero out the 'next' pointer + * because it terminates the xdr_entry recursion + * + * we also must make the filename some non-zero + * char pointer! + */ + + memset(&dummy, 0, sizeof(dummy)); + + dummy.nextentry = 0; + dummy.name = "somename"; /* guess average length of a filename */ + dirres_entry_size = xdr_sizeof(xdr_entry, &dummy); + + assert( smallPool = rpcUdpXactPoolCreate( + NFS_PROGRAM, + NFS_VERSION_2, + CONFIG_NFS_SMALL_XACT_SIZE, + smallPoolDepth) ); + + assert( bigPool = rpcUdpXactPoolCreate( + NFS_PROGRAM, + NFS_VERSION_2, + CONFIG_NFS_BIG_XACT_SIZE, + bigPoolDepth) ); + + assert( RTEMS_SUCCESSFUL == rtems_semaphore_create( + rtems_build_name('N','F','S','l'), + 1, + MUTEX_ATTRIBUTES, + 0, + &nfsGlob.llock) ); + + assert( RTEMS_SUCCESSFUL == rtems_semaphore_create( + rtems_build_name('N','F','S','m'), + 1, + MUTEX_ATTRIBUTES, + 0, + &nfsGlob.lock) ); + + if (sizeof(ino_t) < sizeof(u_int)) { + fprintf(stderr, + "WARNING: Using 'short st_ino' hits performance and may fail to access/find correct files\n"); + fprintf(stderr, + "you should fix newlib's sys/stat.h - for now I'll enable a hack...\n"); + + } +} + +/* Driver cleanup code + */ +int +nfsCleanup(void) +{ +rtems_id l; +int refuse; + + if (!nfsGlob.llock) { + /* registering the driver failed - let them still cleanup */ + return 0; + } + + LOCK(nfsGlob.llock); + if ( (refuse = nfsGlob.num_mounted_fs) ) { + fprintf(stderr,"Refuse to unload NFS; %i filesystems still mounted.\n", + refuse); + nfsMountsShow(stderr); + /* yes, printing is slow - but since you try to unload the driver, + * you assume nobody is using NFS, so what if they have to wait? + */ + UNLOCK(nfsGlob.llock); + return -1; + } + + rtems_semaphore_delete(nfsGlob.lock); + nfsGlob.lock = 0; + + /* hold the lock while cleaning up... */ + + rpcUdpXactPoolDestroy(smallPool); + rpcUdpXactPoolDestroy(bigPool); + l = nfsGlob.llock; + rtems_io_unregister_driver(nfsGlob.nfs_major); + + rtems_semaphore_delete(l); + nfsGlob.llock = 0; + return 0; +} + +/* NFS RPC wrapper. + * + * ARGS: srvr the NFS server we want to call + * proc the NFSPROC_xx we want to invoke + * xargs xdr routine to wrap the arguments + * pargs pointer to the argument object + * xres xdr routine to unwrap the results + * pres pointer to the result object + * + * RETURNS: 0 on success, -1 on error with errno set. + * + * NOTE: the caller assumes that errno is set to + * a nonzero value if this routine returns + * an error (nonzero return value). + * + * This routine prints RPC error messages to + * stderr. + */ +STATIC int +nfscall( + RpcUdpServer srvr, + int proc, + xdrproc_t xargs, + void * pargs, + xdrproc_t xres, + void * pres) +{ +RpcUdpXact xact; +enum clnt_stat stat; +RpcUdpXactPool pool; +int rval = -1; + + + switch (proc) { + case NFSPROC_SYMLINK: + case NFSPROC_WRITE: + pool = bigPool; break; + default: pool = smallPool; break; + } + + xact = rpcUdpXactPoolGet(pool, XactGetCreate); + + if ( !xact ) { + errno = ENOMEM; + return -1; + } + + if ( RPC_SUCCESS != (stat=rpcUdpSend( + xact, + srvr, + NFSCALL_TIMEOUT, + proc, + xres, + pres, + xargs, + pargs, + 0)) || + RPC_SUCCESS != (stat=rpcUdpRcv(xact)) ) { + + fprintf(stderr, + "NFS (proc %i) - %s\n", + proc, + clnt_sperrno(stat)); + + switch (stat) { + /* TODO: this is probably not complete and/or fully accurate */ + case RPC_CANTENCODEARGS : errno = EINVAL; break; + case RPC_AUTHERROR : errno = EPERM; break; + + case RPC_CANTSEND : + case RPC_CANTRECV : /* hope they have errno set */ + case RPC_SYSTEMERROR : break; + + default : errno = EIO; break; + } + } else { + rval = 0; + } + + /* release the transaction back into the pool */ + rpcUdpXactPoolPut(xact); + + if (rval && !errno) + errno = EIO; + + return rval; +} + +/* Check the 'age' of a node's stats + * and read the attributes from the server + * if necessary. + * + * ARGS: node node to update + * force enforce updating ignoring + * the timestamp/age + * + * RETURNS: 0 on success, + * -1 on failure with errno set + */ + +static int +updateAttr(NfsNode node, int force) +{ + + if (force +#ifdef CONFIG_ATTR_LIFETIME + || (nowSeconds() - node->age > CONFIG_ATTR_LIFETIME) +#endif + ) { + if ( nfscall(node->nfs->server, + NFSPROC_GETATTR, + xdr_nfs_fh, &SERP_FILE(node), + xdr_attrstat, &node->serporid) ) + return -1; + + if ( NFS_OK != node->serporid.status ) { + errno = node->serporid.status; + return -1; + } + + node->age = nowSeconds(); + } + + return 0; +} + +/* + * IP address helper. Note that we avoid + * gethostbyname() since it's not reentrant. + * + * initialize a sockaddr_in from a + * ['.''@']':'" string and let + * pPath point to the part; retrieve the optional + * uid/gids + * + * ARGS: see description above + * + * RETURNS: 0 on success, + * -1 on failure with errno set + */ +static int +buildIpAddr(u_long *puid, u_long *pgid, + char **pHost, struct sockaddr_in *psa, + char **pPath) +{ +char host[30]; +char *chpt = *pPath; +char *path; +int len; + + if ( !chpt ) { + errno = EINVAL; + return -1; + } + + /* look for the optional uid/gid */ + if ( (chpt = strchr(chpt, UIDSEP)) ) { + if ( 2 != sscanf(*pPath,"%li.%li",puid,pgid) ) { + errno = EINVAL; + return -1; + } + chpt++; + } else { + *puid = RPCIOD_DEFAULT_ID; + *pgid = RPCIOD_DEFAULT_ID; + chpt = *pPath; + } + if ( pHost ) + *pHost = chpt; + + /* split the device name which is in the form + * + * ':' + * + * into its components using a local buffer + */ + + if ( !(path = strchr(chpt, HOSTDELIM)) || + (len = path - chpt) >= sizeof(host) - 1 ) { + errno = EINVAL; + return -1; + } + /* point to path beyond ':' */ + path++; + + strncpy(host, chpt, len); + host[len]=0; + + if ( ! inet_aton(host, &psa->sin_addr) ) { + errno = ENXIO; + return -1; + } + + psa->sin_family = AF_INET; + psa->sin_port = 0; + *pPath = path; + return 0; +} + +/* wrapper similar to nfscall. + * However, since it is not used + * very often, the simpler and less + * efficient rpcUdpCallRp API is used. + * + * ARGS: see 'nfscall()' above + * + * RETURNS: RPC status + */ +static enum clnt_stat +mntcall( + struct sockaddr_in *psrvr, + int proc, + xdrproc_t xargs, + void * pargs, + xdrproc_t xres, + void * pres, + u_long uid, + u_long gid) +{ +#ifdef MOUNT_V1_PORT +int retry; +#endif +enum clnt_stat stat = RPC_FAILED; + +#ifdef MOUNT_V1_PORT + /* if the portmapper fails, retry a fixed port */ + for (retry = 1, psrvr->sin_port = 0, stat = RPC_FAILED; + retry >= 0 && stat; + stat && (psrvr->sin_port = htons(MOUNT_V1_PORT)), retry-- ) +#endif + stat = rpcUdpCallRp( + psrvr, + MOUNTPROG, + MOUNTVERS, + proc, + xargs, + pargs, + xres, + pres, + uid, + gid, + MNTCALL_TIMEOUT + ); + return stat; +} + +/***************************************** + RTEMS File System Operations for NFS + *****************************************/ + +#if 0 /* for reference */ + +struct rtems_filesystem_location_info_tt +{ + void *node_access; + rtems_filesystem_file_handlers_r *handlers; + rtems_filesystem_operations_table *ops; + rtems_filesystem_mount_table_entry_t *mt_entry; +}; + +#endif + +/* + * Evaluate a path letting 'pathloc' travel along. + * + * The important semantics of this operation are: + * + * If this routine returns -1, the caller assumes + * pathloc to be _invalid_ and hence it will not + * invoke rtems_filesystem_freenode() on it. + * + * OTOH, if evalpath returns 0, + * rtems_filesystem_freenode() will eventually be + * called which results in our freeing the associated + * NfsNode attached to node_access. + * + * Therefore, this routine will _always_ allocate + * a NfsNode and pass it out to *pathloc (provided + * that the evaluation succeeds). + * + * However, if the evaluation finds that it has to + * step across FS boundaries (mount point or a symlink + * pointing outside), the NfsNode is destroyed + * before passing control to the new FS' evalpath_h() + * + */ + +STATIC int nfs_do_evalpath( + const char *pathname, /* IN */ + void *arg, + rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ + int forMake +) +{ +char *del = 0, *part; +int e = 0; +NfsNode node = pathloc->node_access; +char *p = malloc(MAXPATHLEN+1); +Nfs nfs = (Nfs)pathloc->mt_entry->fs_info; +RpcUdpServer server = nfs->server; + + if ( !p ) { + e = ENOMEM; + goto cleanup; + } + strcpy(p, pathname); + + /* clone the node */ + if ( !(node = nfsNodeClone(node)) ) { + /* nodeClone sets errno */ + goto cleanup; + } + + pathloc->node_access = node; + + /* Special case: the RTEMS filesystem code + * may emit '..' on a regular file node to + * find the parent directory :-(. + * (eval.c: rtems_filesystem_evaluate_parent()) + * Try to catch this case here: + */ + if ( NFDIR != SERP_ATTR(node).type && '.'==*p && '.'==*(p+1) ) { + for ( part = p+2; '/'==*part; part++ ) + /* skip trailing '/' */; + if ( !*part ) { + /* this is it; back out dir and let them look up the dir itself... */ + memcpy( &SERP_FILE(node), + &node->args.dir, + sizeof(node->args.dir)); + *(p+1)=0; + } + } + + for (part=p; part && *part; part=del) { + + if ( NFLNK == SERP_ATTR(node).type ) { + /* follow midpath link */ + char *b = malloc(NFS_MAXPATHLEN+1); + int l; + + if (!b) { + e = ENOMEM; + goto cleanup; + } + if (nfs_readlink(pathloc, b, NFS_MAXPATHLEN+1)) { + free(b); + e = errno; + goto cleanup; + } + + /* prepend the link value to the rest of the path */ + if ( (l=strlen(b)) + strlen(part) + 1 > NFS_MAXPATHLEN ) { + free(b); + e = EINVAL; + goto cleanup; + } + /* swap string buffers and reset delimiter */ + b[l++] = DELIM; + strcpy(b+l,part); + part = b; + b = p; + p = del = part; + + free(b); + + /* back up the directory filehandle (only necessary + * if we don't back out to the root + */ + if (! (DELIM == *part) ) { + memcpy( &SERP_FILE(node), + &node->args.dir, + sizeof(node->args.dir)); + + if (updateAttr(node, 1 /* force */)) { + e = errno; + goto cleanup; + } + } + } + + /* find delimiter and eat /// sequences + * (only if we don't restart at the root) + */ + if ( DELIM != *part && (del = strchr(part, DELIM))) { + do { + *del++=0; + } while (DELIM==*del); + } + + /* refuse to backup over the root */ + if ( 0==strcmp(part,UPDIR) + && locAreEqual(pathloc, &rtems_filesystem_root) ) { + part++; + } + + /* cross mountpoint upwards */ + if ( (0==strcmp(part,UPDIR) && locIsRoot(pathloc)) /* cross mountpoint up */ + || DELIM == *part /* link starts at root */ + ) { + int rval; + +#if DEBUG & DEBUG_EVALPATH + fprintf(stderr, + "Crossing mountpoint upwards\n"); +#endif + + if (DELIM == *part) { + *pathloc = rtems_filesystem_root; + } else { + *pathloc = pathloc->mt_entry->mt_point_node; + /* re-append the rest of the path */ + if (del) + while ( 0 == *--del ) + *del = DELIM; + } + + nfsNodeDestroy(node); + +#if DEBUG & DEBUG_EVALPATH + fprintf(stderr, + "Re-evaluating '%s'\n", + part); +#endif + + if (forMake) + rval = pathloc->ops->evalformake_h(part, pathloc, (const char**)arg); + else + rval = pathloc->ops->evalpath_h(part, (int)arg, pathloc); + + free(p); + return rval; + } + + /* lookup one element */ + SERP_ARGS(node).diroparg.name = part; + + /* remember args / directory fh */ + memcpy( &node->args, &SERP_FILE(node), sizeof(node->args)); + + /* don't lookup the item we want to create */ + if ( forMake && (!del || !*del) ) + break; + +#if DEBUG & DEBUG_EVALPATH + fprintf(stderr,"Looking up '%s'\n",part); +#endif + + if ( nfscall(server, + NFSPROC_LOOKUP, + xdr_diropargs, &SERP_FILE(node), + xdr_serporid, &node->serporid) || + NFS_OK != (errno=node->serporid.status) ) { + e = errno; + goto cleanup; + } + node->age = nowSeconds(); + +#if DEBUG & DEBUG_EVALPATH + if (NFLNK == SERP_ATTR(node).type && del) { + fprintf(stderr, + "Following midpath link '%s'\n", + part); + } +#endif + + } + + if (forMake) { + /* remember the name - do this _before_ copying + * the name to local storage; the caller expects a + * pointer into pathloc + */ + assert( node->args.name ); + + *(const char**)arg = pathname + (node->args.name - p); + +#if 0 + /* restore the directory node */ + + memcpy( &SERP_FILE(node), + &node->args.dir, + sizeof(node->args.dir)); + + if ( (nfscall(nfs->server, + NFSPROC_GETATTR, + xdr_nfs_fh, &SERP_FILE(node), + xdr_attrstat, &node->serporid) && !errno && (errno = EIO)) || + (NFS_OK != (errno=node->serporid.status) ) ) { + goto cleanup; + } +#endif + } + + if (locIsRoot(pathloc)) { + + /* stupid filesystem code has no 'op' for comparing nodes + * but just compares the 'node_access' pointers. + * Luckily, this is only done for comparing the root nodes. + * Hence, we never give them a copy of the root but always + * the root itself. + */ + pathloc->node_access = pathloc->mt_entry->mt_fs_root.node_access; + /* increment the 'in use' counter since we return one more + * reference to the root node + */ + LOCK(nfsGlob.lock); + nfs->nodesInUse++; + UNLOCK(nfsGlob.lock); + nfsNodeDestroy(node); + + + } else { + switch (SERP_ATTR(node).type) { + case NFDIR: pathloc->handlers = &nfs_dir_file_handlers; break; + case NFREG: pathloc->handlers = &nfs_file_file_handlers; break; + case NFLNK: pathloc->handlers = &nfs_link_file_handlers; break; + default: pathloc->handlers = &rtems_filesystem_null_handlers; break; + } + pathloc->node_access = node; + + /* remember the name of this directory entry */ + + if (node->args.name) { + if (node->str) { +#if DEBUG & DEBUG_COUNT_NODES + LOCK(nfsGlob.lock); + nfs->stringsInUse--; + UNLOCK(nfsGlob.lock); +#endif + free(node->str); + } + node->args.name = node->str = strdup(node->args.name); + if (!node->str) { + e = ENOMEM; + goto cleanup; + } + +#if DEBUG & DEBUG_COUNT_NODES + LOCK(nfsGlob.lock); + nfs->stringsInUse++; + UNLOCK(nfsGlob.lock); +#endif + } + + } + node = 0; + + e = 0; + +cleanup: + free(p); + if (node) { + nfsNodeDestroy(node); + pathloc->node_access = 0; + } +#if DEBUG & DEBUG_COUNT_NODES + fprintf(stderr, + "leaving evalpath, in use count is %i nodes, %i strings\n", + nfs->nodesInUse, nfs->stringsInUse); +#endif + if (e) { +#if DEBUG & DEBUG_EVALPATH + perror("Evalpath"); +#endif + rtems_set_errno_and_return_minus_one(e); + } else { + return 0; + } +} + +/* MANDATORY; may set errno=ENOSYS and return -1 */ +static int nfs_evalformake( + const char *path, /* IN */ + rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ + const char **pname /* OUT */ +) +{ + return nfs_do_evalpath(path, (void*)pname, pathloc, 1 /*forMake*/); +} + +static int nfs_evalpath( + const char *path, /* IN */ + int flags, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN/OUT */ +) +{ + return nfs_do_evalpath(path, (void*)flags, pathloc, 0 /*not forMake*/); +} + + +/* create a hard link */ + +static int nfs_link( + rtems_filesystem_location_info_t *to_loc, /* IN */ + rtems_filesystem_location_info_t *parent_loc, /* IN */ + const char *name /* IN */ +) +{ +NfsNode pNode; +nfsstat status; +NfsNode tNode = to_loc->node_access; + +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr,"Creating link '%s'\n",name); +#endif + + if ( !locIsNfs(parent_loc) ) { + errno = EXDEV; + return -1; + } + + pNode = parent_loc->node_access; + if ( tNode->nfs != pNode->nfs ) { + errno = EXDEV; + return -1; + } + memcpy(&SERP_ARGS(tNode).linkarg.to.dir, + &SERP_FILE(pNode), + sizeof(SERP_FILE(pNode))); + + SERP_ARGS(tNode).linkarg.to.name = (filename)name; + + if ( nfscall(tNode->nfs->server, + NFSPROC_LINK, + xdr_linkargs, &SERP_FILE(tNode), + xdr_nfsstat, &status) + || (NFS_OK != (errno = status)) + ) { +#if DEBUG & DEBUG_SYSCALLS + perror("nfs_link"); +#endif + return -1; + } + + return 0; + +} + +static int nfs_do_unlink( + rtems_filesystem_location_info_t *loc, /* IN */ + int proc +) +{ +nfsstat status; +NfsNode node = loc->node_access; +Nfs nfs = node->nfs; +#if DEBUG & DEBUG_SYSCALLS +char *name = NFSPROC_REMOVE == proc ? + "nfs_unlink" : "nfs_rmdir"; +#endif + + /* The FS generics have determined that pathloc is _not_ + * a directory. Hence we may assume that the parent + * is in our NFS. + */ + +#if DEBUG & DEBUG_SYSCALLS + assert( node->args.name == node->str && node->str ); + + fprintf(stderr,"%s '%s'\n", name, node->args.name); +#endif + + if ( nfscall(nfs->server, + proc, + xdr_diropargs, &node->args, + xdr_nfsstat, &status) + || (NFS_OK != (errno = status)) + ) { +#if DEBUG & DEBUG_SYSCALLS + perror(name); +#endif + return -1; + } + + return 0; +} + +static int nfs_unlink( + rtems_filesystem_location_info_t *loc /* IN */ +) +{ + return nfs_do_unlink(loc, NFSPROC_REMOVE); +} + +static int nfs_chown( + rtems_filesystem_location_info_t *pathloc, /* IN */ + uid_t owner, /* IN */ + gid_t group /* IN */ +) +{ +sattr arg; + + arg.uid = owner; + arg.gid = group; + + return nfs_sattr(pathloc->node_access, &arg, SATTR_UID | SATTR_GID); + +} + +/* Cleanup the FS private info attached to pathloc->node_access */ +static int nfs_freenode( + rtems_filesystem_location_info_t *pathloc /* IN */ +) +{ +Nfs nfs = ((NfsNode)pathloc->node_access)->nfs; + + /* never destroy the root node; it is released by the unmount + * code + */ + if (locIsRoot(pathloc)) { + /* just adjust the references to the root node but + * don't really release it + */ + LOCK(nfsGlob.lock); + nfs->nodesInUse--; + UNLOCK(nfsGlob.lock); + } else { + nfsNodeDestroy(pathloc->node_access); + pathloc->node_access = 0; + } +#if DEBUG & DEBUG_COUNT_NODES + fprintf(stderr, + "leaving freenode, in use count is %i nodes, %i strings\n", + nfs->nodesInUse, + nfs->stringsInUse); +#endif + return 0; +} + +/* NOTE/TODO: mounting on top of NFS is not currently supported + * + * Challenge: stateless protocol. It would be possible to + * delete mount points on the server. We would need some sort + * of a 'garbage collector' looking for dead/unreachable + * mount points and unmounting them. + * Also, the path evaluation routine would have to check + * for crossing mount points. Crossing over from one NFS + * into another NFS could probably handled iteratively + * rather than by recursion. + */ + +#ifdef DECLARE_BODY +/* This routine is called when they try to mount something + * on top of THIS filesystem, i.e. if one of our directories + * is used as a mount point + */ +static int nfs_mount( + rtems_filesystem_mount_table_entry_t *mt_entry /* in */ +)DECLARE_BODY +#else +#define nfs_mount 0 +#endif + +#ifdef DECLARE_BODY +/* This op is called when they try to unmount a FS + * from a mountpoint managed by THIS FS. + */ +static int nfs_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry /* in */ +)DECLARE_BODY +#else +#define nfs_unmount 0 +#endif + +#if 0 + +/* for reference (libio.h) */ + +struct rtems_filesystem_mount_table_entry_tt { + Chain_Node Node; + rtems_filesystem_location_info_t mt_point_node; + rtems_filesystem_location_info_t mt_fs_root; + int options; + void *fs_info; + + rtems_filesystem_limits_and_options_t pathconf_limits_and_options; + + /* + * When someone adds a mounted filesystem on a real device, + * this will need to be used. + * + * The best option long term for this is probably an open file descriptor. + */ + char *dev; +}; +#endif + + +/* This op is called as the last step of mounting this FS */ +STATIC int nfs_fsmount_me( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ +char *host; +struct sockaddr_in saddr; +enum clnt_stat stat; +fhstatus fhstat; +u_long uid,gid; +#ifdef NFS_V2_PORT +int retry; +#endif +Nfs nfs = 0; +NfsNode rootNode = 0; +RpcUdpServer nfsServer = 0; +int e = -1; +char *path = mt_entry->dev; + + + if ( buildIpAddr(&uid, &gid, &host, &saddr, &path) ) + return -1; + + +#ifdef NFS_V2_PORT + /* if the portmapper fails, retry a fixed port */ + for (retry = 1, saddr.sin_port = 0, stat = RPC_FAILED; + retry >= 0 && stat; + stat && (saddr.sin_port = htons(NFS_V2_PORT)), retry-- ) +#endif + stat = rpcUdpServerCreate( + &saddr, + NFS_PROGRAM, + NFS_VERSION_2, + uid, + gid, + &nfsServer + ); + + if ( RPC_SUCCESS != stat ) { + fprintf(stderr, + "Unable to contact NFS server - invalid port? (%s)\n", + clnt_sperrno(stat)); + e = EPROTONOSUPPORT; + goto cleanup; + } + + + /* first, try to ping the NFS server by + * calling the NULL proc. + */ + if ( nfscall(nfsServer, + NFSPROC_NULL, + xdr_void, 0, + xdr_void, 0) ) { + + fputs("NFS Ping ",stderr); + fwrite(host, 1, path-host-1, stderr); + fprintf(stderr," failed: %s\n", strerror(errno)); + + e = errno ? errno : EIO; + goto cleanup; + } + + /* that seemed to work - we now try the + * actual mount + */ + + /* reuse server address but let the mntcall() + * search for the mountd's port + */ + saddr.sin_port = 0; + + stat = mntcall( &saddr, + MOUNTPROC_MNT, + xdr_dirpath, + &path, + xdr_fhstatus, + &fhstat, + uid, + gid ); + + if (stat) { + fprintf(stderr,"MOUNT -- %s\n",clnt_sperrno(stat)); + if ( e<=0 ) + e = EIO; + goto cleanup; + } else if (NFS_OK != (e=fhstat.fhs_status)) { + fprintf(stderr,"MOUNT: %s\n",strerror(e)); + goto cleanup; + } + + assert( nfs = nfsCreate(nfsServer) ); + nfsServer = 0; + + nfs->uid = uid; + nfs->gid = gid; + + /* that seemed to work - we now create the root node + * and we also must obtain the root node attributes + */ + assert( rootNode = nfsNodeCreate(nfs, (nfs_fh*)&fhstat.fhstatus_u.fhs_fhandle ) ); + + if ( updateAttr(rootNode, 1 /* force */) ) { + e = errno; + goto cleanup; + } + + /* looks good so far */ + + mt_entry->mt_fs_root.node_access = rootNode; + + rootNode = 0; + + mt_entry->mt_fs_root.ops = &nfs_fs_ops; + mt_entry->mt_fs_root.handlers = &nfs_dir_file_handlers; + mt_entry->pathconf_limits_and_options = nfs_limits_and_options; + + LOCK(nfsGlob.llock); + nfsGlob.num_mounted_fs++; + /* allocate a new ID for this FS */ + nfs->id = nfsGlob.fs_ids++; + UNLOCK(nfsGlob.llock); + + mt_entry->fs_info = nfs; + nfs->mt_entry = mt_entry; + nfs = 0; + + e = 0; + +cleanup: + if (nfs) + nfsDestroy(nfs); + if (nfsServer) + rpcUdpServerDestroy(nfsServer); + if (rootNode) + nfsNodeDestroy(rootNode); + if (e) + rtems_set_errno_and_return_minus_one(e); + else + return 0; +} + +/* This op is called when they try to unmount THIS fs */ +STATIC int nfs_fsunmount_me( + rtems_filesystem_mount_table_entry_t *mt_entry /* in */ +) +{ +enum clnt_stat stat; +struct sockaddr_in saddr; +char *path = mt_entry->dev; +int nodesInUse; +u_long uid,gid; + + LOCK(nfsGlob.lock); + nodesInUse = ((Nfs)mt_entry->fs_info)->nodesInUse; + UNLOCK(nfsGlob.lock); + + if (nodesInUse > 1 /* one ref to the root node used by us */) { + fprintf(stderr, + "Refuse to unmount; there are still %i nodes in use (1 used by us)\n", + nodesInUse); + rtems_set_errno_and_return_minus_one(EBUSY); + } + + assert( 0 == buildIpAddr(&uid, &gid, 0, &saddr, &path) ); + + stat = mntcall( &saddr, + MOUNTPROC_UMNT, + xdr_dirpath, &path, + xdr_void, 0, + uid, + gid + ); + + if (stat) { + fprintf(stderr,"NFS UMOUNT -- %s\n", clnt_sperrno(stat)); + errno = EIO; + return -1; + } + + nfsNodeDestroy(mt_entry->mt_fs_root.node_access); + mt_entry->mt_fs_root.node_access = 0; + + nfsDestroy(mt_entry->fs_info); + mt_entry->fs_info = 0; + + LOCK(nfsGlob.llock); + nfsGlob.num_mounted_fs--; + UNLOCK(nfsGlob.llock); + + return 0; +} + +/* OPTIONAL; may be NULL - BUT: CAUTION; mount() doesn't check + * for this handler to be present - a fs bug + * //NOTE: (10/25/2002) patch submitted and probably applied + */ +static rtems_filesystem_node_types_t nfs_node_type( + rtems_filesystem_location_info_t *pathloc /* in */ +) +{ +NfsNode node = pathloc->node_access; + + if (updateAttr(node, 0 /* only if old */)) + return -1; + + switch( SERP_ATTR(node).type ) { + default: + /* rtems has no value for 'unknown'; + */ + case NFNON: + case NFSOCK: + case NFBAD: + case NFFIFO: + break; + + + case NFREG: return RTEMS_FILESYSTEM_MEMORY_FILE; + case NFDIR: return RTEMS_FILESYSTEM_DIRECTORY; + + case NFBLK: + case NFCHR: return RTEMS_FILESYSTEM_DEVICE; + + case NFLNK: return RTEMS_FILESYSTEM_SYM_LINK; + } + return -1; +} + +static int nfs_mknod( + const char *path, /* IN */ + mode_t mode, /* IN */ + dev_t dev, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN/OUT */ +) +{ +rtems_clock_time_value now; +diropres res; +NfsNode node = pathloc->node_access; +mode_t type = S_IFMT & mode; + + if (type != S_IFDIR && type != S_IFREG) + rtems_set_errno_and_return_minus_one(ENOTSUP); + +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr,"nfs_mknod: creating %s\n", path); +#endif + + rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); + + SERP_ARGS(node).createarg.name = (filename)path; + SERP_ARGS(node).createarg.attributes.mode = mode; + /* TODO: either use our uid or use the Nfs credentials */ + SERP_ARGS(node).createarg.attributes.uid = 0; + SERP_ARGS(node).createarg.attributes.gid = 0; + SERP_ARGS(node).createarg.attributes.size = 0; + SERP_ARGS(node).createarg.attributes.atime.seconds = now.seconds; + SERP_ARGS(node).createarg.attributes.atime.useconds = now.microseconds; + SERP_ARGS(node).createarg.attributes.mtime.seconds = now.seconds; + SERP_ARGS(node).createarg.attributes.mtime.useconds = now.microseconds; + + if ( nfscall( node->nfs->server, + NFSPROC_CREATE, + xdr_createargs, &SERP_FILE(node), + xdr_diropres, &res) + || (NFS_OK != (errno = res.status)) ) { +#if DEBUG & DEBUG_SYSCALLS + perror("nfs_mknod"); +#endif + return -1; + } + + return 0; +} + +static int nfs_utime( + rtems_filesystem_location_info_t *pathloc, /* IN */ + time_t actime, /* IN */ + time_t modtime /* IN */ +) +{ +sattr arg; + + /* TODO: add rtems EPOCH - UNIX EPOCH seconds */ + arg.atime.seconds = actime; + arg.atime.useconds = 0; + arg.mtime.seconds = modtime; + arg.mtime.useconds = 0; + + return nfs_sattr(pathloc->node_access, &arg, SATTR_ATIME | SATTR_MTIME); +} + +static int nfs_symlink( + rtems_filesystem_location_info_t *loc, /* IN */ + const char *link_name, /* IN */ + const char *node_name +) +{ +rtems_clock_time_value now; +nfsstat status; +NfsNode node = loc->node_access; + + +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr,"nfs_symlink: creating %s -> %s\n", link_name, node_name); +#endif + + rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); + + SERP_ARGS(node).symlinkarg.name = (filename)link_name; + SERP_ARGS(node).symlinkarg.to = (nfspath) node_name; + + SERP_ARGS(node).symlinkarg.attributes.mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + /* TODO */ + SERP_ARGS(node).symlinkarg.attributes.uid = 0; + SERP_ARGS(node).symlinkarg.attributes.gid = 0; + SERP_ARGS(node).symlinkarg.attributes.size = 0; + SERP_ARGS(node).symlinkarg.attributes.atime.seconds = now.seconds; + SERP_ARGS(node).symlinkarg.attributes.atime.useconds = now.microseconds; + SERP_ARGS(node).symlinkarg.attributes.mtime.seconds = now.seconds; + SERP_ARGS(node).symlinkarg.attributes.mtime.useconds = now.microseconds; + + if ( nfscall( node->nfs->server, + NFSPROC_SYMLINK, + xdr_symlinkargs, &SERP_FILE(node), + xdr_nfsstat, &status) + || (NFS_OK != (errno = status)) ) { +#if DEBUG & DEBUG_SYSCALLS + perror("nfs_symlink"); +#endif + return -1; + } + + return 0; +} + +static int nfs_do_readlink( + rtems_filesystem_location_info_t *loc, /* IN */ + strbuf *psbuf /* IN/OUT */ +) +{ +NfsNode node = loc->node_access; +Nfs nfs = node->nfs; +readlinkres_strbuf rr; +int wasAlloced; +int rval; + + rr.strbuf = *psbuf; + + wasAlloced = (0 == psbuf->buf); + + if ( (rval = nfscall(nfs->server, + NFSPROC_READLINK, + xdr_nfs_fh, &SERP_FILE(node), + xdr_readlinkres_strbuf, &rr)) ) { + if (wasAlloced) + xdr_free( xdr_strbuf, (caddr_t)&rr.strbuf ); + } + + + if (NFS_OK != rr.status) { + if (wasAlloced) + xdr_free( xdr_strbuf, (caddr_t)&rr.strbuf ); + rtems_set_errno_and_return_minus_one(rr.status); + } + + *psbuf = rr.strbuf; + + return 0; +} + +static int nfs_readlink( + rtems_filesystem_location_info_t *loc, /* IN */ + char *buf, /* OUT */ + size_t len +) +{ +strbuf sbuf; + sbuf.buf = buf; + sbuf.max = len; + + return nfs_do_readlink(loc, &sbuf); +} + +/* The semantics of this routine are: + * + * The caller submits a valid pathloc, i.e. it has + * an NfsNode attached to node_access. + * On return, pathloc points to the target node which + * may or may not be an NFS node. + * Hence, the original NFS node is released in either + * case: + * - link evaluation fails; pathloc points to no valid node + * - link evaluation success; pathloc points to a new valid + * node. If it's an NFS node, a new NfsNode will be attached + * to node_access... + */ + +#define LINKVAL_BUFLEN (MAXPATHLEN+1) +#define RVAL_ERR_BUT_DONT_FREENODE (-1) +#define RVAL_ERR_AND_DO_FREENODE ( 1) +#define RVAL_OK ( 0) + +static int nfs_eval_link( + rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ + int flags /* IN */ +) +{ +rtems_filesystem_node_types_t type; +char *buf = malloc(LINKVAL_BUFLEN); +int rval = RVAL_ERR_AND_DO_FREENODE; + + if (!buf) { + errno = ENOMEM; + goto cleanup; + } + + /* in this loop, we must not use NFS specific ops as we might + * step out of our FS during the process... + * This algorithm should actually be performed by the + * generic's evaluate_path routine :-( + * + * Unfortunately, there is no way of finding the + * directory node who contains 'pathloc', however :-( + */ + do { + /* assume the generics have verified 'pathloc' to be + * a link... + */ + if ( !pathloc->ops->readlink_h ) { + errno = ENOTSUP; + goto cleanup; + } + + if ( pathloc->ops->readlink_h(pathloc, buf, LINKVAL_BUFLEN) ) { + goto cleanup; + } + +#if DEBUG & DEBUG_EVALPATH + fprintf(stderr, "link value is '%s'\n", buf); +#endif + + /* is the link value an absolute path ? */ + if ( DELIM != *buf ) { + /* NO; a relative path */ + + /* we must backup to the link's directory - we + * know only how to do that for NFS, however. + * In this special case, we can avoid recursion. + * Otherwise (i.e. if the link is on another FS), + * we must step into its eval_link_h(). + */ + if (locIsNfs(pathloc)) { + NfsNode node = pathloc->node_access; + int err; + + memcpy( &SERP_FILE(node), + &node->args.dir, + sizeof(node->args.dir) ); + + if (updateAttr(node, 1 /* force */)) + goto cleanup; + + if (SERP_ATTR(node).type != NFDIR) { + errno = ENOTDIR; + goto cleanup; + } + + pathloc->handlers = &nfs_dir_file_handlers; + + err = nfs_evalpath(buf, flags, pathloc); + + /* according to its semantics, + * nfs_evalpath cloned the node attached + * to pathloc. Hence we have to + * release the old one (referring to + * the link; the new clone has been + * updated and refers to the link _value_). + */ + nfsNodeDestroy(node); + + if (err) { + /* nfs_evalpath has set errno; + * pathloc->node_access has no + * valid node attached in this case + */ + rval = RVAL_ERR_BUT_DONT_FREENODE; + goto cleanup; + } + + } else { + if ( ! pathloc->ops->eval_link_h ) { + errno = ENOTSUP; + goto cleanup; + } + if (!pathloc->ops->eval_link_h(pathloc, flags)) { + /* FS is responsible for freeing its pathloc->node_access + * if necessary + */ + rval = RVAL_ERR_BUT_DONT_FREENODE; + goto cleanup; + } + } + } else { + /* link points to an absolute path '/xxx' */ + + /* release this node; filesystem_evaluate_path() will + * lookup a new one. + */ + rtems_filesystem_freenode(pathloc); + + if (rtems_filesystem_evaluate_path(buf, flags, pathloc, 1)) { + goto cleanup; + } + } + + if ( !pathloc->ops->node_type_h ) { + errno = ENOTSUP; + goto cleanup; + } + + type = pathloc->ops->node_type_h(pathloc); + + + /* I dont know what to do about hard links */ + } while ( RTEMS_FILESYSTEM_SYM_LINK == type ); + + rval = RVAL_OK; + +cleanup: + + free(buf); + + if (RVAL_ERR_AND_DO_FREENODE == rval) { + rtems_filesystem_freenode(pathloc); + return -1; + } + + return rval; +} + + +struct _rtems_filesystem_operations_table nfs_fs_ops = { + nfs_evalpath, /* MANDATORY */ + nfs_evalformake, /* MANDATORY; may set errno=ENOSYS and return -1 */ + nfs_link, /* OPTIONAL; may be NULL */ + nfs_unlink, /* OPTIONAL; may be NULL */ + nfs_node_type, /* OPTIONAL; may be NULL; BUG in mount - no test!! */ + nfs_mknod, /* OPTIONAL; may be NULL */ + nfs_chown, /* OPTIONAL; may be NULL */ + nfs_freenode, /* OPTIONAL; may be NULL; (release node_access) */ + nfs_mount, /* OPTIONAL; may be NULL */ + nfs_fsmount_me, /* OPTIONAL; may be NULL -- but this makes NO SENSE */ + nfs_unmount, /* OPTIONAL; may be NULL */ + nfs_fsunmount_me, /* OPTIONAL; may be NULL */ + nfs_utime, /* OPTIONAL; may be NULL */ + nfs_eval_link, /* OPTIONAL; may be NULL */ + nfs_symlink, /* OPTIONAL; may be NULL */ + nfs_readlink, /* OPTIONAL; may be NULL */ +}; + +/***************************************** + File Handlers + + NOTE: the FS generics expect a FS' + evalpath_h() to switch the + pathloc->handlers according + to the pathloc/node's file + type. + We currently have 'file' and + 'directory' handlers and very + few 'symlink' handlers. + + The handlers for each type are + implemented or #defined ZERO + in a 'nfs_file_xxx', + 'nfs_dir_xxx', 'nfs_link_xxx' + sequence below this point. + + In some cases, a common handler, + can be used for all file types. + It is then simply called + 'nfs_xxx'. + *****************************************/ + + +#if 0 +/* from rtems/libio.h for convenience */ +struct rtems_libio_tt { + rtems_driver_name_t *driver; + off_t size; /* size of file */ + off_t offset; /* current offset into file */ + unsigned32 flags; + rtems_filesystem_location_info_t pathinfo; + Objects_Id sem; + unsigned32 data0; /* private to "driver" */ + void *data1; /* ... */ + void *file_info; /* used by file handlers */ + rtems_filesystem_file_handlers_r *handlers; /* type specific handlers */ +}; +#endif + +/* stateless NFS protocol makes this trivial */ +static int nfs_file_open( + rtems_libio_t *iop, + const char *pathname, + unsigned32 flag, + unsigned32 mode +) +{ + iop->file_info = 0; + return 0; +} + +/* reading directories is not stateless; we must + * remember the last 'read' position, i.e. + * the server 'cookie'. We do manage this information + * attached to the iop->file_info. + */ +static int nfs_dir_open( + rtems_libio_t *iop, + const char *pathname, + unsigned32 flag, + unsigned32 mode +) +{ +NfsNode node = iop->pathinfo.node_access; +DirInfo di; + + /* create a readdirargs object and copy the file handle; + * attach to the file_info. + */ + + di = (DirInfo) malloc(sizeof(*di)); + iop->file_info = di; + + if ( !di ) { + errno = ENOMEM; + return -1; + } + + memcpy( &di->readdirargs.dir, + &SERP_FILE(node), + sizeof(di->readdirargs.dir) ); + + /* rewind cookie */ + memset( &di->readdirargs.cookie, + 0, + sizeof(di->readdirargs.cookie) ); + + di->eofreached = FALSE; + + return 0; +} + +#define nfs_link_open 0 + +static int nfs_file_close( + rtems_libio_t *iop +) +{ + return 0; +} + +static int nfs_dir_close( + rtems_libio_t *iop +) +{ + free(iop->file_info); + iop->file_info = 0; + return 0; +} + +#define nfs_link_close 0 + +static int nfs_file_read( + rtems_libio_t *iop, + void *buffer, + unsigned32 count +) +{ +readres rr; +NfsNode node = iop->pathinfo.node_access; +Nfs nfs = node->nfs; + + if (count > NFS_MAXDATA) + count = NFS_MAXDATA; + + SERP_ARGS(node).readarg.offset = iop->offset; + SERP_ARGS(node).readarg.count = count; + SERP_ARGS(node).readarg.totalcount = 0xdeadbeef; + + rr.readres_u.reply.data.data_val = buffer; + + if ( nfscall( nfs->server, + NFSPROC_READ, + xdr_readargs, &SERP_FILE(node), + xdr_readres, &rr) ) { + return -1; + } + + + if (NFS_OK != rr.status) { + rtems_set_errno_and_return_minus_one(rr.status); + } + +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr, + "Read %i (asked for %i) bytes from offset %i to 0x%08x\n", + rr.readres_u.reply.data.data_len, + count, + iop->offset, + rr.readres_u.reply.data.data_val); +#endif + + + return rr.readres_u.reply.data.data_len; +} + +/* this is called by readdir() / getdents() */ +static int nfs_dir_read( + rtems_libio_t *iop, + void *buffer, + unsigned32 count +) +{ +DirInfo di = iop->file_info; +RpcUdpServer server = ((Nfs)iop->pathinfo.mt_entry->fs_info)->server; + + if ( di->eofreached ) + return 0; + + di->ptr = di->buf = buffer; + + /* align + round down the buffer */ + count &= ~ (DIRENT_HEADER_SIZE - 1); + di->len = count; + +#if 0 + /* now estimate the number of entries we should ask for */ + count /= DIRENT_HEADER_SIZE + CONFIG_AVG_NAMLEN; + + /* estimate the encoded size that might take up */ + count *= dirres_entry_size + CONFIG_AVG_NAMLEN; +#else + /* integer arithmetics are better done the other way round */ + count *= dirres_entry_size + CONFIG_AVG_NAMLEN; + count /= DIRENT_HEADER_SIZE + CONFIG_AVG_NAMLEN; +#endif + + if (count > NFS_MAXDATA) + count = NFS_MAXDATA; + + di->readdirargs.count = count; + +#if DEBUG & DEBUG_READDIR + fprintf(stderr, + "Readdir: asking for %i XDR bytes, buffer is %i\n", + count, di->len); +#endif + + if ( nfscall( + server, + NFSPROC_READDIR, + xdr_readdirargs, &di->readdirargs, + xdr_dir_info, di) ) { + return -1; + } + + + if (NFS_OK != di->status) { + rtems_set_errno_and_return_minus_one(di->status); + } + + return (char*)di->ptr - (char*)buffer; +} + +#define nfs_link_read 0 + +static int nfs_file_write( + rtems_libio_t *iop, + const void *buffer, + unsigned32 count +) +{ +NfsNode node = iop->pathinfo.node_access; +Nfs nfs = node->nfs; +int e; + + if (count > NFS_MAXDATA) + count = NFS_MAXDATA; + + SERP_ARGS(node).writearg.beginoffset = 0xdeadbeef; + SERP_ARGS(node).writearg.offset = iop->offset; + SERP_ARGS(node).writearg.totalcount = 0xdeadbeef; + SERP_ARGS(node).writearg.data.data_len = count; + SERP_ARGS(node).writearg.data.data_val = (void*)buffer; + + /* write XDR buffer size will be chosen by nfscall based + * on the PROC specifier + */ + + if ( nfscall( nfs->server, + NFSPROC_WRITE, + xdr_writeargs, &SERP_FILE(node), + xdr_attrstat, &node->serporid) ) { + return -1; + } + + + if (NFS_OK != (e=node->serporid.status) ) { + /* try at least to recover the current attributes */ + updateAttr(node, 1 /* force */); + rtems_set_errno_and_return_minus_one(e); + } + + node->age = nowSeconds(); + + return count; +} + +#define nfs_dir_write 0 +#define nfs_link_write 0 + +/* IOCTL is unneeded/unsupported */ +#ifdef DECLARE_BODY +static int nfs_file_ioctl( + rtems_libio_t *iop, + unsigned32 command, + void *buffer +)DECLARE_BODY +#else +#define nfs_file_ioctl 0 +#define nfs_dir_ioctl 0 +#define nfs_link_ioctl 0 +#endif + +static int nfs_file_lseek( + rtems_libio_t *iop, + off_t length, + int whence +) +{ +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr, + "lseek to %i (length %i, whence %i)\n", + iop->offset, + length, + whence); +#endif + + /* this is particularly easy :-) */ + return iop->offset; +} + +static int nfs_dir_lseek( + rtems_libio_t *iop, + off_t length, + int whence +) +{ +DirInfo di = iop->file_info; + + /* we don't support anything other than + * rewinding + */ + if (SEEK_SET != whence || 0 != length) { + errno = ENOTSUP; + return -1; + } + + /* rewind cookie */ + memset( &di->readdirargs.cookie, + 0, + sizeof(di->readdirargs.cookie) ); + + di->eofreached = FALSE; + + return iop->offset; +} + +#define nfs_link_lseek 0 + +#if 0 /* structure types for reference */ +struct fattr { + ftype type; + u_int mode; + u_int nlink; + u_int uid; + u_int gid; + u_int size; + u_int blocksize; + u_int rdev; + u_int blocks; + u_int fsid; + u_int fileid; + nfstime atime; + nfstime mtime; + nfstime ctime; +}; + +struct stat +{ + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + /* SysV/sco doesn't have the rest... But Solaris, eabi does. */ +#if defined(__svr4__) && !defined(__PPC__) && !defined(__sun__) + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +#else + time_t st_atime; + long st_spare1; + time_t st_mtime; + long st_spare2; + time_t st_ctime; + long st_spare3; + long st_blksize; + long st_blocks; + long st_spare4[2]; +#endif +}; +#endif + +/* common for file/dir/link */ +static int nfs_fstat( + rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ +NfsNode node = loc->node_access; +fattr *fa = &SERP_ATTR(node); + + if (updateAttr(node, 0 /* only if old */)) { + return -1; + } + +/* done by caller + memset(buf, 0, sizeof(*buf)); + */ + + /* translate */ + + /* one of the branches hopefully is optimized away */ + if (sizeof(ino_t) < sizeof(u_int)) { + buf->st_dev = NFS_MAKE_DEV_T_INO_HACK((NfsNode)loc->node_access); + } else { + buf->st_dev = NFS_MAKE_DEV_T((NfsNode)loc->node_access); + } + buf->st_mode = fa->mode; + buf->st_nlink = fa->nlink; + buf->st_uid = fa->uid; + buf->st_gid = fa->gid; + buf->st_size = fa->size; + /* TODO: set to "preferred size" of this NFS client implementation */ + buf->st_blksize = fa->blocksize; + buf->st_rdev = fa->rdev; + buf->st_blocks = fa->blocks; + buf->st_ino = fa->fileid; + buf->st_atime = fa->atime.seconds; + buf->st_mtime = fa->mtime.seconds; + buf->st_ctime = fa->ctime.seconds; + +#if 0 /* NFS should return the modes */ + switch(fa->type) { + default: + case NFNON: + case NFBAD: + break; + + case NFSOCK: buf->st_mode |= S_IFSOCK; break; + case NFFIFO: buf->st_mode |= S_IFIFO; break; + case NFREG : buf->st_mode |= S_IFREG; break; + case NFDIR : buf->st_mode |= S_IFDIR; break; + case NFBLK : buf->st_mode |= S_IFBLK; break; + case NFCHR : buf->st_mode |= S_IFCHR; break; + case NFLNK : buf->st_mode |= S_IFLNK; break; + } +#endif + + return 0; +} + +/* a helper which does the real work for + * a couple of handlers (such as chmod, + * ftruncate or utime) + */ +static int +nfs_sattr(NfsNode node, sattr *arg, u_long mask) +{ + +rtems_clock_time_value now; +nfstime nfsnow, t; +int e; +u_int mode; + + if (updateAttr(node, 0 /* only if old */)) + return -1; + + rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE, &now); + + /* TODO: add rtems EPOCH - UNIX EPOCH seconds */ + nfsnow.seconds = now.seconds; + nfsnow.useconds = now.microseconds; + + /* merge permission bits into existing type bits */ + mode = SERP_ATTR(node).mode; + if (mask & SATTR_MODE) { + mode &= S_IFMT; + mode |= arg->mode & ~S_IFMT; + } + SERP_ARGS(node).sattrarg.attributes.mode = mode; + + SERP_ARGS(node).sattrarg.attributes.uid = + (mask & SATTR_UID) ? arg->uid : SERP_ATTR(node).uid; + + SERP_ARGS(node).sattrarg.attributes.gid = + (mask & SATTR_GID) ? arg->gid : SERP_ATTR(node).gid; + + SERP_ARGS(node).sattrarg.attributes.size = + (mask & SATTR_SIZE) ? arg->size : SERP_ATTR(node).size; + + if (mask & SATTR_ATIME) + t = arg->atime; + else if (mask & SATTR_TOUCHA) + t = nfsnow; + else + t = SERP_ATTR(node).atime; + SERP_ARGS(node).sattrarg.attributes.atime = t; + + if (mask & SATTR_ATIME) + t = arg->mtime; + else if (mask & SATTR_TOUCHA) + t = nfsnow; + else + t = SERP_ATTR(node).mtime; + SERP_ARGS(node).sattrarg.attributes.mtime = t; + + node->serporid.status = NFS_OK; + + if ( nfscall( node->nfs->server, + NFSPROC_SETATTR, + xdr_sattrargs, &SERP_FILE(node), + xdr_attrstat, &node->serporid) ) { +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr, + "nfs_sattr (mask 0x%08x): %s", + mask, + strerror(errno)); +#endif + return -1; + } + + if (NFS_OK != (e=node->serporid.status) ) { +#if DEBUG & DEBUG_SYSCALLS + fprintf(stderr,"nfs_sattr: %s\n",strerror(e)); +#endif + /* try at least to recover the current attributes */ + updateAttr(node, 1 /* force */); + rtems_set_errno_and_return_minus_one(e); + } + + node->age = nowSeconds(); + + return 0; +} + + +/* common for file/dir/link */ +static int nfs_fchmod( + rtems_filesystem_location_info_t *loc, + mode_t mode +) +{ +sattr arg; + + arg.mode = mode; + return nfs_sattr(loc->node_access, &arg, SATTR_MODE); + +} + +/* just set the size attribute to 'length' + * the server will take care of the rest :-) + */ +static int nfs_file_ftruncate( + rtems_libio_t *iop, + off_t length +) +{ +sattr arg; + + arg.size = length; + return nfs_sattr(iop->pathinfo.node_access, + &arg, + SATTR_SIZE | SATTR_TOUCH); +} + +#define nfs_dir_ftruncate 0 +#define nfs_link_ftruncate 0 + +/* not implemented */ +#ifdef DECLARE_BODY +static int nfs_file_fpathconf( + rtems_libio_t *iop, + int name +)DECLARE_BODY +#else +#define nfs_file_fpathconf 0 +#define nfs_dir_fpathconf 0 +#define nfs_link_fpathconf 0 +#endif + +/* unused */ +#ifdef DECLARE_BODY +static int nfs_file_fsync( + rtems_libio_t *iop +)DECLARE_BODY +#else +#define nfs_file_fsync 0 +#define nfs_dir_fsync 0 +#define nfs_link_fsync 0 +#endif + +/* unused */ +#ifdef DECLARE_BODY +static int nfs_file_fdatasync( + rtems_libio_t *iop +)DECLARE_BODY +#else +#define nfs_file_fdatasync 0 +#define nfs_dir_fdatasync 0 +#define nfs_link_fdatasync 0 +#endif + +/* unused */ +#ifdef DECLARE_BODY +static int nfs_file_fcntl( + int cmd, + rtems_libio_t *iop +)DECLARE_BODY +#else +#define nfs_file_fcntl 0 +#define nfs_dir_fcntl 0 +#define nfs_link_fcntl 0 +#endif + +/* files and symlinks are removed + * by the common nfs_unlink() routine. + * NFS has a different NFSPROC_RMDIR + * call, though... + */ +static int nfs_dir_rmnod( + rtems_filesystem_location_info_t *pathloc /* IN */ +) +{ + return nfs_do_unlink(pathloc, NFSPROC_RMDIR); +} + +/* the file handlers table */ +static +struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers = { + nfs_file_open, /* OPTIONAL; may be NULL */ + nfs_file_close, /* OPTIONAL; may be NULL */ + nfs_file_read, /* OPTIONAL; may be NULL */ + nfs_file_write, /* OPTIONAL; may be NULL */ + nfs_file_ioctl, /* OPTIONAL; may be NULL */ + nfs_file_lseek, /* OPTIONAL; may be NULL */ + nfs_fstat, /* OPTIONAL; may be NULL */ + nfs_fchmod, /* OPTIONAL; may be NULL */ + nfs_file_ftruncate, /* OPTIONAL; may be NULL */ + nfs_file_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ + nfs_file_fsync, /* OPTIONAL; may be NULL */ + nfs_file_fdatasync, /* OPTIONAL; may be NULL */ + nfs_file_fcntl, /* OPTIONAL; may be NULL */ + nfs_unlink, /* OPTIONAL; may be NULL */ +}; + +/* the directory handlers table */ +static +struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers = { + nfs_dir_open, /* OPTIONAL; may be NULL */ + nfs_dir_close, /* OPTIONAL; may be NULL */ + nfs_dir_read, /* OPTIONAL; may be NULL */ + nfs_dir_write, /* OPTIONAL; may be NULL */ + nfs_dir_ioctl, /* OPTIONAL; may be NULL */ + nfs_dir_lseek, /* OPTIONAL; may be NULL */ + nfs_fstat, /* OPTIONAL; may be NULL */ + nfs_fchmod, /* OPTIONAL; may be NULL */ + nfs_dir_ftruncate, /* OPTIONAL; may be NULL */ + nfs_dir_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ + nfs_dir_fsync, /* OPTIONAL; may be NULL */ + nfs_dir_fdatasync, /* OPTIONAL; may be NULL */ + nfs_dir_fcntl, /* OPTIONAL; may be NULL */ + nfs_dir_rmnod, /* OPTIONAL; may be NULL */ +}; + +/* the link handlers table */ +static +struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers = { + nfs_link_open, /* OPTIONAL; may be NULL */ + nfs_link_close, /* OPTIONAL; may be NULL */ + nfs_link_read, /* OPTIONAL; may be NULL */ + nfs_link_write, /* OPTIONAL; may be NULL */ + nfs_link_ioctl, /* OPTIONAL; may be NULL */ + nfs_link_lseek, /* OPTIONAL; may be NULL */ + nfs_fstat, /* OPTIONAL; may be NULL */ + nfs_fchmod, /* OPTIONAL; may be NULL */ + nfs_link_ftruncate, /* OPTIONAL; may be NULL */ + nfs_link_fpathconf, /* OPTIONAL; may be NULL - UNUSED */ + nfs_link_fsync, /* OPTIONAL; may be NULL */ + nfs_link_fdatasync, /* OPTIONAL; may be NULL */ + nfs_link_fcntl, /* OPTIONAL; may be NULL */ + nfs_unlink, /* OPTIONAL; may be NULL */ +}; + +/* we need a dummy driver entry table to get a + * major number from the system + */ +static +rtems_device_driver nfs_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + /* we don't really use this routine because + * we cannot supply an argument (contrary + * to what the 'arg' parameter suggests - it + * is always set to 0 by the generics :-() + * and because we don't want the user to + * have to deal with the major number (which + * OTOH is something WE are interested in. The + * only reason for using this API was getting + * a major number, after all). + * + * Something must be present, however, to + * reserve a slot in the driver table. + */ + return RTEMS_SUCCESSFUL; +} + +static rtems_driver_address_table drvNfs = { + nfs_initialize, + 0, /* open */ + 0, /* close */ + 0, /* read */ + 0, /* write */ + 0 /* control */ +}; + +/* Dump a list of the currently mounted NFS to a file */ +int +nfsMountsShow(FILE *f) +{ +char *mntpt = 0; +Nfs nfs; + + if (!f) + f = stdout; + + if ( !(mntpt=malloc(MAXPATHLEN)) ) { + fprintf(stderr,"nfsMountsShow(): no memory\n"); + return -1; + } + + fprintf(f,"Currently Mounted NFS:\n"); + + LOCK(nfsGlob.llock); + + for (nfs = nfsGlob.mounted_fs; nfs; nfs=nfs->next) { + fprintf(f,"%s on ", nfs->mt_entry->dev); + if (rtems_filesystem_resolve_location(mntpt, MAXPATHLEN, &nfs->mt_entry->mt_fs_root)) + fprintf(f,"\n"); + else + fprintf(f,"%s\n",mntpt); + } + + UNLOCK(nfsGlob.llock); + + free(mntpt); + return 0; +} + +/* convenience wrapper + * + * NOTE: this routine calls NON-REENTRANT + * gethostbyname() if the host is + * not in 'dot' notation. + */ +int +nfsMount(char *uidhost, char *path, char *mntpoint) +{ +rtems_filesystem_mount_table_entry_t *mtab; +struct stat st; +int devl; +char *host; +int rval = -1; +char *dev = 0; + + if (!uidhost || !path || !mntpoint) { + fprintf(stderr,"usage: nfsMount(""[uid.gid@]host"",""path"",""mountpoint"")\n"); + nfsMountsShow(stderr); + return -1; + } + + if ( !(dev = malloc((devl=strlen(uidhost) + 20 + strlen(path)+1))) ) { + fprintf(stderr,"nfsMount: out of memory\n"); + return -1; + } + + /* Try to create the mount point if nonexistent */ + if (stat(mntpoint, &st)) { + if (ENOENT != errno) { + perror("nfsMount trying to create mount point - stat failed"); + goto cleanup; + } else if (mkdir(mntpoint,0777)) { + perror("nfsMount trying to create mount point"); + goto cleanup; + } + } + + if ( !(host=strchr(uidhost,UIDSEP)) ) { + host = uidhost; + } else { + host++; + } + + if (isdigit(*host)) { + /* avoid using gethostbyname */ + sprintf(dev,"%s:%s",uidhost,path); + } else { + struct hostent *h; + + /* copy the uid part (hostname will be + * overwritten) + */ + strcpy(dev, uidhost); + + /* NOTE NOTE NOTE: gethostbyname is NOT + * thread safe. This is UGLY + */ + +/* BEGIN OF NON-THREAD SAFE REGION */ + + h = gethostbyname(host); + + if ( !h || + !inet_ntop( AF_INET, + (struct in_addr*)h->h_addr_list[0], + dev + (host - uidhost), + devl - (host - uidhost) ) + ) { + fprintf(stderr,"nfsMount: host '%s' not found\n",host); + goto cleanup; + } + +/* END OF NON-THREAD SAFE REGION */ + + /* append ':' */ + strcat(dev,":"); + strcat(dev,path); + } + + printf("Trying to mount %s on %s\n",dev,mntpoint); + + if (mount(&mtab, + &nfs_fs_ops, + RTEMS_FILESYSTEM_READ_WRITE, + dev, + mntpoint)) { + perror("nfsMount - mount"); + goto cleanup; + } + + rval = 0; + +cleanup: + free(dev); + return rval; +} + +/* HERE COMES A REALLY UGLY HACK */ + +/* This is stupid; it is _very_ hard to find the path + * leading to a rtems_filesystem_location_info_t node :-( + * The only easy way is making the location the current + * directory and issue a getcwd(). + * However, since we don't want to tamper with the + * current directory, we must create a separate + * task to do the job for us - sigh. + */ + +typedef struct ResolvePathArgRec_ { + rtems_filesystem_location_info_t *loc; /* IN: location to resolve */ + char *buf; /* IN/OUT: buffer where to put the path */ + int len; /* IN: buffer length */ + rtems_id sync; /* IN: synchronization */ + rtems_status_code status; /* OUT: result */ +} ResolvePathArgRec, *ResolvePathArg; + +static void +resolve_path(rtems_task_argument arg) +{ +ResolvePathArg rpa = (ResolvePathArg)arg; +rtems_filesystem_location_info_t old; + + /* IMPORTANT: let the helper task have its own libio environment (i.e. cwd) */ + if (RTEMS_SUCCESSFUL == (rpa->status = rtems_libio_set_private_env())) { + + old = rtems_filesystem_current; + + rtems_filesystem_current = *(rpa->loc); + + if ( !getcwd(rpa->buf, rpa->len) ) + rpa->status = RTEMS_UNSATISFIED; + + /* must restore the cwd because 'freenode' will be called on it */ + rtems_filesystem_current = old; + } + rtems_semaphore_release(rpa->sync); + rtems_task_delete(RTEMS_SELF); +} + + +/* a utility routine to find the path leading to a + * rtems_filesystem_location_info_t node + * + * INPUT: 'loc' and a buffer 'buf' (length 'len') to hold the + * path. + * OUTPUT: path copied into 'buf' + * + * RETURNS: 0 on success, RTEMS error code on error. + */ +rtems_status_code +rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc) +{ +ResolvePathArgRec arg; +rtems_id tid = 0; +rtems_task_priority pri; +rtems_status_code status; + + arg.loc = loc; + arg.buf = buf; + arg.len = len; + arg.sync = 0; + + status = rtems_semaphore_create( + rtems_build_name('r','e','s','s'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &arg.sync); + + if (RTEMS_SUCCESSFUL != status) + goto cleanup; + + rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &pri); + + status = rtems_task_create( + rtems_build_name('r','e','s','s'), + pri, + RTEMS_MINIMUM_STACK_SIZE + 50000, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &tid); + + if (RTEMS_SUCCESSFUL != status) + goto cleanup; + + status = rtems_task_start(tid, resolve_path, (rtems_task_argument)&arg); + + if (RTEMS_SUCCESSFUL != status) { + rtems_task_delete(tid); + goto cleanup; + } + + + /* synchronize with the helper task */ + rtems_semaphore_obtain(arg.sync, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + + status = arg.status; + +cleanup: + if (arg.sync) + rtems_semaphore_delete(arg.sync); + + return status; +} diff --git a/rtemsNfs/src/nfs.modini.c b/rtemsNfs/src/nfs.modini.c new file mode 100644 index 0000000..834102e --- /dev/null +++ b/rtemsNfs/src/nfs.modini.c @@ -0,0 +1,27 @@ +#include "librtemsNfs.h" + +/* CEXP dynamic loader support */ + +void +_cexpModuleInitialize(void *mod) +{ +#if defined(DEBUG) + /* print load address (in case we crash while initializing) */ +unsigned lr; + __asm__ __volatile__( + " bl thisis_loaded_at \n" + "thisis_loaded_at: \n" + " mflr %0 \n" + : "=r"(lr) ::"lr"); + printf("thisis_loaded_at: 0x%08x\n",lr); +#endif + nfsInit(0,0); +} + +int +_cexpModuleFinalize(void *mod) +{ + return nfsCleanup(); +} + + diff --git a/rtemsNfs/src/rpcio.c b/rtemsNfs/src/rpcio.c new file mode 100644 index 0000000..667ba6a --- /dev/null +++ b/rtemsNfs/src/rpcio.c @@ -0,0 +1,1717 @@ +/* $Id$ */ + +/* RPC multiplexor for a multitasking environment */ + +/* Author: Till Straumann , 2002 */ + +/* This code funnels arbitrary task's UDP/RPC requests + * through one socket to arbitrary servers. + * The replies are gathered and dispatched to the + * requestors. + * One task handles all the sending and receiving + * work including retries. + * It is up to the requestor, however, to do + * the XDR encoding of the arguments / decoding + * of the results (except for the RPC header which + * is handled by the daemon). + * + * Copyright 2002, Stanford University and + * Till Straumann + * + * Stanford Notice + * *************** + * + * Acknowledgement of sponsorship + * * * * * * * * * * * * * * * * * + * This software was produced by the Stanford Linear Accelerator Center, + * Stanford University, under Contract DE-AC03-76SFO0515 with the Department + * of Energy. + * + * Government disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, + * or assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately + * owned rights. + * + * Stanford disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * This product is subject to the EPICS open license + * - - - - - - - - - - - - - - - - - - - - - - - - - + * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php + * for more information. + * + * Maintenance of notice + * - - - - - - - - - - - + * In the interest of clarity regarding the origin and status of this + * software, Stanford University requests that any recipient of it maintain + * this notice affixed to any distribution by the recipient that contains a + * copy or derivative of this software. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpcio.h" + +/****************************************************************/ +/* CONFIGURABLE PARAMETERS */ +/****************************************************************/ + +#define MBUF_RX /* If defined: use mbuf XDR stream for + * decoding directly out of mbufs + * Otherwise, the regular 'recvfrom()' + * interface will be used involving an + * extra buffer allocation + copy step. + */ + +#define MBUF_TX /* If defined: avoid copying data when + * sending. Instead, use a wrapper to + * 'sosend()' which will point an MBUF + * directly to our buffer space. + * Note that the BSD stack does not copy + * data when fragmenting packets - it + * merely uses an mbuf chain pointing + * into different areas of the data. + * + * If undefined, the regular 'sendto()' + * interface is used. + */ + +/* daemon task parameters */ +#define RPCIOD_STACK 10000 +#define RPCIOD_PRIO 50 + +/* depth of the message queue for sending + * RPC requests to the daemon + */ +#define RPCIOD_QDEPTH 20 + +/* Maximum retry limit for retransmission */ +#define RPCIOD_RETX_CAP_S 3 /* seconds */ + +/* Default timeout for RPC calls */ +#define RPCIOD_DEFAULT_TIMEOUT (&_rpc_default_timeout) +static struct timeval _rpc_default_timeout = { 10 /* secs */, 0 /* usecs */ }; + +/* how many times should we try to resend a failed + * transaction with refreshed AUTHs + */ +#define RPCIOD_REFRESH 2 + +/* Events we are using; the RPC_EVENT + * MUST NOT be used by any application + * thread doing RPC IO (e.g. NFS) + */ +#define RTEMS_RPC_EVENT RTEMS_EVENT_30 /* THE event used by RPCIO. Every task doing + * RPC IO will receive this - hence it is + * RESERVED + */ +#define RPCIOD_RX_EVENT RTEMS_EVENT_1 /* Events the RPCIOD is using/waiting for */ +#define RPCIOD_TX_EVENT RTEMS_EVENT_2 +#define RPCIOD_KILL_EVENT RTEMS_EVENT_3 /* send to the daemon to kill it */ + +#define LD_XACT_HASH 8 /* ld of the size of the transaction hash table */ + + +/* Debugging Flags */ + +/* NOTE: defining DEBUG 0 leaves some 'assert()' paranoia checks + * but produces no output + */ + +#define DEBUG_TRACE_XACT (1<<0) +#define DEBUG_EVENTS (1<<1) +#define DEBUG_MALLOC (1<<2) +#define DEBUG_TIMEOUT (1<<3) +#define DEBUG_PACKLOSS (1<<4) /* This introduces random, artificial packet losses to test retransmission */ + +#define DEBUG_PACKLOSS_FRACT (0xffffffff/10) + +/* USE PARENTHESIS WHEN 'or'ing MULTIPLE FLAGS: (DEBUG_XX | DEBUG_YY) */ +#define DEBUG (0) + +/****************************************************************/ +/* END OF CONFIGURABLE SECTION */ +/****************************************************************/ + +/* prevent rollover of our timers by readjusting the epoch on the fly */ +#if (DEBUG) & DEBUG_TIMEOUT +#define RPCIOD_EPOCH_SECS 10 +#else +#define RPCIOD_EPOCH_SECS 10000 +#endif + +#ifdef DEBUG +#define ASSERT(arg) assert(arg) +#else +#define ASSERT(arg) if (arg) +#endif + +/****************************************************************/ +/* MACROS */ +/****************************************************************/ + + +#define XACT_HASHS (1<<(LD_XACT_HASH)) /* the hash table size derived from the ld */ +#define XACT_HASH_MSK ((XACT_HASHS)-1) /* mask to extract the hash index from a RPC-XID */ + + +#define MU_LOCK(mutex) do { \ + assert( \ + RTEMS_SUCCESSFUL == \ + rtems_semaphore_obtain( \ + (mutex), \ + RTEMS_WAIT, \ + RTEMS_NO_TIMEOUT \ + ) ); \ + } while(0) + +#define MU_UNLOCK(mutex) do { \ + assert( \ + RTEMS_SUCCESSFUL == \ + rtems_semaphore_release( \ + (mutex) \ + ) ); \ + } while(0) + +#define MU_CREAT(pmutex) do { \ + assert( \ + RTEMS_SUCCESSFUL == \ + rtems_semaphore_create( \ + rtems_build_name( \ + 'R','P','C','l' \ + ), \ + 1, \ + MUTEX_ATTRIBUTES, \ + 0, \ + (pmutex)) ); \ + } while (0) + + +#define MU_DESTROY(mutex) do { \ + assert( \ + RTEMS_SUCCESSFUL == \ + rtems_semaphore_delete( \ + mutex \ + ) ); \ + } while (0) + +#define MUTEX_ATTRIBUTES (RTEMS_LOCAL | \ + RTEMS_PRIORITY | \ + RTEMS_INHERIT_PRIORITY | \ + RTEMS_BINARY_SEMAPHORE) + +#define FIRST_ATTEMPT 0x88888888 /* some time that is never reached */ + +/****************************************************************/ +/* TYPE DEFINITIONS */ +/****************************************************************/ + +typedef rtems_interval TimeoutT; + +/* 100000th implementation of a doubly linked list; + * since only one thread is looking at these, + * we need no locking + */ +typedef struct ListNodeRec_ { + struct ListNodeRec_ *next, *prev; +} ListNodeRec, *ListNode; + + +/* Structure representing an RPC server */ +typedef struct RpcUdpServerRec_ { + RpcUdpServer next; /* linked list of all servers; protected by hlock */ + struct sockaddr_in addr; + AUTH *auth; + rtems_id authlock; /* must MUTEX the auth object - it's not clear + * what is better: + * 1 having one (MUTEXed) auth per server + * who is shared among all transactions + * using that server + * 2 maintaining an AUTH per transaction + * (there are then other options: manage + * XACT pools on a per-server basis instead + * of associating a server with a XACT when + * sending) + * experience will show if the current (1) + * approach has to be changed. + */ + TimeoutT retry_period; /* dynamically adjusted retry period + * (based on packet roundtrip time) + */ + /* STATISTICS */ + unsigned long retrans; /* how many retries were issued by this server */ + unsigned long requests; /* how many requests have been sent */ + unsigned long timeouts; /* how many requests have timed out */ + unsigned long errors; /* how many errors have occurred (other than timeouts) */ + char name[20]; /* server's address in IP 'dot' notation */ +} RpcUdpServerRec; + +typedef union RpcBufU_ { + u_long xid; + char buf[1]; +} RpcBufU, *RpcBuf; + +/* RX Buffer implementation; this is either + * an MBUF chain (MBUF_RX configuration) + * or a buffer allocated from the heap + * where recvfrom copies the (encoded) reply + * to. The XDR routines the copy/decode + * it into the user's data structures. + */ +#ifdef MBUF_RX +typedef struct mbuf * RxBuf; /* an MBUF chain */ +static void bufFree(struct mbuf **m); +#define XID(ibuf) (*(mtod((ibuf), u_long *))) +extern void xdrmbuf_create(XDR *, struct mbuf *, enum xdr_op); +#else +typedef RpcBuf RxBuf; +#define bufFree(b) do { MY_FREE(*(b)); *(b)=0; } while(0) +#define XID(ibuf) ((ibuf)->xid) +#endif + +/* A RPC 'transaction' consisting + * of server and requestor information, + * buffer space and an XDR object + * (for encoding arguments). + */ +typedef struct RpcUdpXactRec_ { + ListNodeRec node; /* so we can put XACTs on a list */ + RpcUdpServer server; /* server this XACT goes to */ + long lifetime; /* during the lifetime, retry attempts are made */ + long tolive; /* lifetime timer */ + struct rpc_err status; /* RPC reply error status */ + long age; /* age info; needed to manage retransmission */ + long trip; /* record round trip time in ticks */ + rtems_id requestor; /* the task waiting for this XACT to complete */ + RpcUdpXactPool pool; /* if this XACT belong to a pool, this is it */ + XDR xdrs; /* argument encoder stream */ + int xdrpos; /* stream position after the (permanent) header */ + xdrproc_t xres; /* reply decoder proc - TODO needn't be here */ + caddr_t pres; /* reply decoded obj - TODO needn't be here */ +#ifndef MBUF_RX + int ibufsize; /* size of the ibuf (bytes) */ +#endif +#ifdef MBUF_TX + int refcnt; /* mbuf external storage reference count */ +#endif + int obufsize; /* size of the obuf (bytes) */ + RxBuf ibuf; /* pointer to input buffer assigned by daemon */ + RpcBufU obuf; /* output buffer (encoded args) APPENDED HERE */ +} RpcUdpXactRec; + +typedef struct RpcUdpXactPoolRec_ { + rtems_id box; + int prog; + int version; + int xactSize; +} RpcUdpXactPoolRec; + +/* a global hash table where all 'living' transaction + * objects are registered. + * A number of bits in a transaction's XID maps 1:1 to + * an index in this table. Hence, the XACT matching + * an RPC/UDP reply packet can quickly be found + * The size of this table imposes a hard limit on the + * number of all created transactions in the system. + */ +static RpcUdpXact xactHashTbl[XACT_HASHS]={0}; + +/* forward declarations */ +static RpcUdpXact +sockRcv(void); + +static void +rpcio_daemon(rtems_task_argument); + +#ifdef MBUF_TX +ssize_t +sendto_nocpy ( + int s, + const void *buf, size_t buflen, + int flags, + const struct sockaddr *toaddr, int tolen, + void *closure, + void (*freeproc)(caddr_t, u_int), + void (*refproc)(caddr_t, u_int) +); +static void paranoia_free(caddr_t closure, u_int size); +static void paranoia_ref (caddr_t closure, u_int size); +#define SENDTO sendto_nocpy +#else +#define SENDTO sendto +#endif + +static RpcUdpServer rpcUdpServers = 0; /* linked list of all servers; protected by llock */ + +static int ourSock = -1; /* the socket we are using for communication */ +static rtems_id rpciod = 0; /* task id of the RPC daemon */ +static rtems_id msgQ = 0; /* message queue where the daemon picks up + * requests + */ +static rtems_id llock = 0; /* MUTEX protecting the server list */ +static rtems_id hlock = 0; /* MUTEX protecting the hash table and the list of servers */ +static rtems_id fini = 0; /* a synchronization semaphore we use during + * module cleanup / driver unloading + */ +static rtems_interval ticksPerSec; /* cached system clock rate (WHO IS ASSUMED NOT + * TO CHANGE) + */ +#if (DEBUG) & DEBUG_MALLOC +/* malloc wrappers for debugging */ +static int nibufs = 0; + +static inline void *MY_MALLOC(int s) +{ + if (s) { + void *rval; + MU_LOCK(hlock); + assert(nibufs++ < 2000); + MU_UNLOCK(hlock); + assert(rval = malloc(s)); + return rval; + } + return 0; +} + +static inline void *MY_CALLOC(int n, int s) +{ + if (s) { + void *rval; + MU_LOCK(hlock); + assert(nibufs++ < 2000); + MU_UNLOCK(hlock); + assert(rval = calloc(n,s)); + return rval; + } + return 0; +} + + +static inline void MY_FREE(void *p) +{ + if (p) { + MU_LOCK(hlock); + nibufs--; + MU_UNLOCK(hlock); + free(p); + } +} +#else +#define MY_MALLOC malloc +#define MY_CALLOC calloc +#define MY_FREE free +#endif + +static inline bool_t +locked_marshal(RpcUdpServer s, XDR *xdrs) +{ +bool_t rval; + MU_LOCK(s->authlock); + rval = AUTH_MARSHALL(s->auth, xdrs); + MU_UNLOCK(s->authlock); + return rval; +} + +/* Locked operations on a server's auth object */ +static inline bool_t +locked_validate(RpcUdpServer s, struct opaque_auth *v) +{ +bool_t rval; + MU_LOCK(s->authlock); + rval = AUTH_VALIDATE(s->auth, v); + MU_UNLOCK(s->authlock); + return rval; +} + +static inline bool_t +locked_refresh(RpcUdpServer s) +{ +bool_t rval; + MU_LOCK(s->authlock); + rval = AUTH_REFRESH(s->auth); + MU_UNLOCK(s->authlock); + return rval; +} + +/* Create a server object + * + */ +enum clnt_stat +rpcUdpServerCreate( + struct sockaddr_in *paddr, + int prog, + int vers, + u_long uid, + u_long gid, + RpcUdpServer *psrv + ) +{ +RpcUdpServer rval; +u_short port; +char hname[MAX_MACHINE_NAME + 1]; +int theuid, thegid; +int thegids[NGRPS]; +gid_t gids[NGROUPS]; +int len,i; +AUTH *auth; +enum clnt_stat pmap_err; +struct pmap pmaparg; + + if ( gethostname(hname, MAX_MACHINE_NAME) ) { + fprintf(stderr, + "RPCIO - error: I have no hostname ?? (%s)\n", + strerror(errno)); + return RPC_UNKNOWNHOST; + } + + if ( (len = getgroups(NGROUPS, gids) < 0 ) ) { + fprintf(stderr, + "RPCIO - error: I unable to get group ids (%s)\n", + strerror(errno)); + return RPC_FAILED; + } + + if ( len > NGRPS ) + len = NGRPS; + + for (i=0; isin_port) { + + paddr->sin_port = htons(PMAPPORT); + + pmaparg.pm_prog = prog; + pmaparg.pm_vers = vers; + pmaparg.pm_prot = IPPROTO_UDP; + pmaparg.pm_port = 0; /* not needed or used */ + + + /* dont use non-reentrant pmap_getport ! */ + + pmap_err = rpcUdpCallRp( + paddr, + PMAPPROG, + PMAPVERS, + PMAPPROC_GETPORT, + xdr_pmap, + &pmaparg, + xdr_u_short, + &port, + uid, + gid, + 0); + + if ( RPC_SUCCESS != pmap_err ) { + paddr->sin_port = 0; + return pmap_err; + } + + paddr->sin_port = htons(port); + } + + if (0==paddr->sin_port) { + return RPC_PROGNOTREGISTERED; + } + + rval = (RpcUdpServer)MY_MALLOC(sizeof(*rval)); + memset(rval, 0, sizeof(*rval)); + + if (!inet_ntop(AF_INET, &paddr->sin_addr, rval->name, sizeof(rval->name))) + sprintf(rval->name,"?.?.?.?"); + rval->addr = *paddr; + + /* start with a long retransmission interval - it + * will be adapted dynamically + */ + rval->retry_period = RPCIOD_RETX_CAP_S * ticksPerSec; + + rval->auth = auth; + + MU_CREAT( &rval->authlock ); + + /* link into list */ + MU_LOCK( llock ); + rval->next = rpcUdpServers; + rpcUdpServers = rval; + MU_UNLOCK( llock ); + + *psrv = rval; + return RPC_SUCCESS; +} + +void +rpcUdpServerDestroy(RpcUdpServer s) +{ +RpcUdpServer prev; + if (!s) + return; + /* we should probably verify (but how?) that nobody + * (at least: no outstanding XACTs) is using this + * server; + */ + + /* remove from server list */ + MU_LOCK(llock); + prev = rpcUdpServers; + if ( s == prev ) { + rpcUdpServers = s->next; + } else { + for ( ; prev ; prev = prev->next) { + if (prev->next == s) { + prev->next = s->next; + break; + } + } + } + MU_UNLOCK(llock); + + /* MUST have found it */ + assert(prev); + + auth_destroy(s->auth); + + MU_DESTROY(s->authlock); + MY_FREE(s); +} + +int +rpcUdpStats(FILE *f) +{ +RpcUdpServer s; + + if (!f) f = stdout; + + fprintf(f,"RPCIOD statistics:\n"); + + MU_LOCK(llock); + for (s = rpcUdpServers; s; s=s->next) { + fprintf(f,"\nServer -- %s:\n", s->name); + fprintf(f," requests sent: %10ld, retransmitted: %10ld\n", + s->requests, s->retrans); + fprintf(f," timed out: %10ld, send errors: %10ld\n", + s->timeouts, s->errors); + fprintf(f," current retransmission interval: %dms\n", + s->retry_period * 1000 / ticksPerSec ); + } + MU_UNLOCK(llock); + + return 0; +} + +RpcUdpXact +rpcUdpXactCreate( + u_long program, + u_long version, + u_long size + ) +{ +RpcUdpXact rval=0; +struct rpc_msg header; +register int i,j; + + if (!size) + size = UDPMSGSIZE; + /* word align */ + size = (size + 3) & ~3; + + rval = (RpcUdpXact)MY_CALLOC(1,sizeof(*rval) - sizeof(rval->obuf) + size); + + if (rval) { + + header.rm_xid = 0; + header.rm_direction = CALL; + header.rm_call.cb_rpcvers = RPC_MSG_VERSION; + header.rm_call.cb_prog = program; + header.rm_call.cb_vers = version; + xdrmem_create(&(rval->xdrs), rval->obuf.buf, size, XDR_ENCODE); + + if (!xdr_callhdr(&(rval->xdrs), &header)) { + MY_FREE(rval); + return 0; + } + /* pick a free table slot and initialize the XID */ + rval->obuf.xid = time(0) ^ (unsigned long)rval; + MU_LOCK(hlock); + i=j=(rval->obuf.xid & XACT_HASH_MSK); + if (msgQ) { + /* if there's no message queue, refuse to + * give them transactions; we might be in the process to + * go away... + */ + do { + i=(i+1) & XACT_HASH_MSK; /* cheap modulo */ + if (!xactHashTbl[i]) { +#if (DEBUG) & DEBUG_TRACE_XACT + fprintf(stderr,"RPCIO: entering index %i, val %x\n",i,rval); +#endif + xactHashTbl[i]=rval; + j=-1; + break; + } + } while (i!=j); + } + MU_UNLOCK(hlock); + if (i==j) { + XDR_DESTROY(&rval->xdrs); + MY_FREE(rval); + return 0; + } + rval->obuf.xid = (rval->obuf.xid << LD_XACT_HASH) | i; + rval->xdrpos = XDR_GETPOS(&(rval->xdrs)); + rval->obufsize = size; + } + return rval; +} + +void +rpcUdpXactDestroy(RpcUdpXact xact) +{ +int i = xact->obuf.xid & XACT_HASH_MSK; + +#if (DEBUG) & DEBUG_TRACE_XACT + fprintf(stderr,"RPCIO: removing index %i, val %x\n",i,xact); +#endif + + ASSERT( xactHashTbl[i]==xact ); + + MU_LOCK(hlock); + xactHashTbl[i]=0; + MU_UNLOCK(hlock); + + bufFree(&xact->ibuf); + + XDR_DESTROY(&xact->xdrs); + MY_FREE(xact); +} + + + +/* Send a transaction, i.e. enqueue it to the + * RPC daemon who will actually send it. + */ +enum clnt_stat +rpcUdpSend( + RpcUdpXact xact, + RpcUdpServer srvr, + struct timeval *timeout, + u_long proc, + xdrproc_t xres, caddr_t pres, + xdrproc_t xargs, caddr_t pargs, + ... + ) +{ +register XDR *xdrs; +unsigned long ms; +va_list ap; + + va_start(ap,pargs); + + if (!timeout) + timeout = RPCIOD_DEFAULT_TIMEOUT; + + ms = 1000 * timeout->tv_sec + timeout->tv_usec/1000; + + xact->lifetime = ms * ticksPerSec / 1000; +#if (DEBUG) & DEBUG_TIMEOUT + { + static int once=0; + if (!once++) { + fprintf(stderr, + "Initial lifetime: %i (ticks)\n", + xact->lifetime); + } + } +#endif + + xact->tolive = xact->lifetime; + + xact->xres = xres; + xact->pres = pres; + xact->server = srvr; + + xdrs = &xact->xdrs; + xdrs->x_op = XDR_ENCODE; + /* increment transaction ID */ + xact->obuf.xid += XACT_HASHS; + XDR_SETPOS(xdrs, xact->xdrpos); + if ( !XDR_PUTLONG(xdrs,&proc) || !locked_marshal(srvr, xdrs) || + !xargs(xdrs, pargs) ) { + va_end(ap); + return(xact->status.re_status=RPC_CANTENCODEARGS); + } + while ((xargs=va_arg(ap,xdrproc_t))) { + if (!xargs(xdrs, va_arg(ap,caddr_t))) + va_end(ap); + return(xact->status.re_status=RPC_CANTENCODEARGS); + } + + va_end(ap); + + rtems_task_ident(RTEMS_SELF, RTEMS_WHO_AM_I, &xact->requestor); + if ( rtems_message_queue_send( msgQ, &xact, sizeof(xact)) ) { + return RPC_CANTSEND; + } + /* wakeup the rpciod */ + ASSERT( RTEMS_SUCCESSFUL==rtems_event_send(rpciod, RPCIOD_TX_EVENT) ); + + return RPC_SUCCESS; +} + +/* Block for the RPC reply to an outstanding + * transaction. + * The caller is woken by the RPC daemon either + * upon reception of the reply or on timeout. + */ +enum clnt_stat +rpcUdpRcv(RpcUdpXact xact) +{ +int refresh; +XDR reply_xdrs; +struct rpc_msg reply_msg; +rtems_event_set gotEvents; + + refresh = 0; + + do { + + /* block for the reply */ + ASSERT( RTEMS_SUCCESSFUL == + rtems_event_receive( + RTEMS_RPC_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &gotEvents) ); + + if (xact->status.re_status) { +#ifdef MBUF_RX + /* add paranoia */ + ASSERT( !xact->ibuf ); +#endif + return xact->status.re_status; + } + +#ifdef MBUF_RX + xdrmbuf_create(&reply_xdrs, xact->ibuf, XDR_DECODE); +#else + xdrmem_create(&reply_xdrs, xact->ibuf->buf, xact->ibufsize, XDR_DECODE); +#endif + + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = xact->pres; + reply_msg.acpted_rply.ar_results.proc = xact->xres; + + if (xdr_replymsg(&reply_xdrs, &reply_msg)) { + /* OK */ + _seterr_reply(&reply_msg, &xact->status); + if (RPC_SUCCESS == xact->status.re_status) { + if ( !locked_validate(xact->server, + &reply_msg.acpted_rply.ar_verf) ) { + xact->status.re_status = RPC_AUTHERROR; + xact->status.re_why = AUTH_INVALIDRESP; + } + if (reply_msg.acpted_rply.ar_verf.oa_base) { + reply_xdrs.x_op = XDR_FREE; + xdr_opaque_auth(&reply_xdrs, &reply_msg.acpted_rply.ar_verf); + } + refresh = 0; + } else { + /* should we try to refresh our credentials ? */ + if ( !refresh ) { + /* had never tried before */ + refresh = RPCIOD_REFRESH; + } + } + } else { + reply_xdrs.x_op = XDR_FREE; + xdr_replymsg(&reply_xdrs, &reply_msg); + xact->status.re_status = RPC_CANTDECODERES; + } + XDR_DESTROY(&reply_xdrs); + + bufFree(&xact->ibuf); + +#ifndef MBUF_RX + xact->ibufsize = 0; +#endif + + if (refresh && locked_refresh(xact->server)) { + rtems_task_ident(RTEMS_SELF, RTEMS_WHO_AM_I, &xact->requestor); + if ( rtems_message_queue_send(msgQ, &xact, sizeof(xact)) ) { + return RPC_CANTSEND; + } + /* wakeup the rpciod */ + fprintf(stderr,"RPCIO INFO: refreshing my AUTH\n"); + ASSERT( RTEMS_SUCCESSFUL==rtems_event_send(rpciod, RPCIOD_TX_EVENT) ); + } + + } while ( 0 && refresh-- > 0 ); + + return xact->status.re_status; +} + + +/* On RTEMS, I'm told to avoid select(); this seems to + * be more efficient + */ +static void +rxWakeupCB(struct socket *sock, caddr_t arg) +{ +rtems_event_send((rtems_id)arg, RPCIOD_RX_EVENT); +} + +int +rpcUdpInit(void) +{ +int noblock = 1; +struct sockwakeup wkup; + + fprintf(stderr,"This is RTEMS-RPCIOD Release $Name$\n"); + fprintf(stderr,"($Id$)\n\n"); + fprintf(stderr,"Till Straumann, Stanford/SLAC/SSRL 2002\n"); + fprintf(stderr,"See LICENSE file for licensing info\n"); + + if (ourSock < 0) { + ourSock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ourSock>=0) { + bindresvport(ourSock,(struct sockaddr_in*)0); + assert( 0==ioctl(ourSock, FIONBIO, (char*)&noblock) ); + /* assume nobody tampers with the clock !! */ + assert( RTEMS_SUCCESSFUL == rtems_clock_get( + RTEMS_CLOCK_GET_TICKS_PER_SECOND, + &ticksPerSec)); + MU_CREAT( &hlock ); + MU_CREAT( &llock ); + + assert( RTEMS_SUCCESSFUL == rtems_task_create( + rtems_build_name('R','P','C','d'), + RPCIOD_PRIO, + RPCIOD_STACK, + RTEMS_DEFAULT_MODES, + /* fprintf saves/restores FP registers on PPC :-( */ + RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, + &rpciod) ); + wkup.sw_pfn = rxWakeupCB; + wkup.sw_arg = (caddr_t)rpciod; + assert( 0==setsockopt(ourSock, SOL_SOCKET, SO_RCVWAKEUP, &wkup, sizeof(wkup)) ); + assert( RTEMS_SUCCESSFUL == rtems_message_queue_create( + rtems_build_name('R','P','C','q'), + RPCIOD_QDEPTH, + sizeof(RpcUdpXact), + RTEMS_DEFAULT_ATTRIBUTES, + &msgQ) ); + assert( RTEMS_SUCCESSFUL == rtems_task_start( + rpciod, + rpcio_daemon, + 0 ) ); + + } else { + return -1; + } + } + return 0; +} + +int +rpcUdpCleanup(void) +{ + rtems_semaphore_create( + rtems_build_name('R','P','C','f'), + 0, + RTEMS_DEFAULT_ATTRIBUTES, + 0, + &fini); + rtems_event_send(rpciod, RPCIOD_KILL_EVENT); + /* synchronize with daemon */ + rtems_semaphore_obtain(fini, RTEMS_WAIT, 5*ticksPerSec); + /* if the message queue is still there, something went wrong */ + if (!msgQ) { + rtems_task_delete(rpciod); + } + rtems_semaphore_delete(fini); + return (msgQ !=0); +} + +/* Another API - simpler but less efficient. + * For each RPCall, a server and a Xact + * are created and destroyed on the fly. + * + * This should be used for infrequent calls + * (e.g. a NFS mount request). + * + * This is roughly compatible with the original + * clnt_call() etc. API - but it uses our + * daemon and is fully reentrant. + */ +enum clnt_stat +rpcUdpClntCreate( + struct sockaddr_in *psaddr, + int prog, + int vers, + u_long uid, + u_long gid, + RpcUdpClnt *pclnt +) +{ +RpcUdpXact x; +RpcUdpServer s; +enum clnt_stat err; + + if ( RPC_SUCCESS != (err=rpcUdpServerCreate(psaddr, prog, vers, uid, gid, &s)) ) + return err; + + if ( !(x=rpcUdpXactCreate(prog, vers, UDPMSGSIZE)) ) { + rpcUdpServerDestroy(s); + return RPC_FAILED; + } + /* TODO: could maintain a server cache */ + + x->server = s; + + *pclnt = x; + + return RPC_SUCCESS; +} + +void +rpcUdpClntDestroy(RpcUdpClnt xact) +{ + rpcUdpServerDestroy(xact->server); + rpcUdpXactDestroy(xact); +} + +enum clnt_stat +rpcUdpClntCall( + RpcUdpClnt xact, + u_long proc, + XdrProcT xargs, + CaddrT pargs, + XdrProcT xres, + CaddrT pres, + struct timeval *timeout + ) +{ +enum clnt_stat stat; + + if ( (stat = rpcUdpSend(xact, xact->server, timeout, proc, + xres, pres, + xargs, pargs, + 0)) ) { + fprintf(stderr,"RPCIO Send failed: %i\n",stat); + return stat; + } + return rpcUdpRcv(xact); +} + +/* a yet simpler interface */ +enum clnt_stat +rpcUdpCallRp( + struct sockaddr_in *psrvr, + u_long prog, + u_long vers, + u_long proc, + XdrProcT xargs, + CaddrT pargs, + XdrProcT xres, + CaddrT pres, + u_long uid, /* RPCIO_DEFAULT_ID picks default */ + u_long gid, /* RPCIO_DEFAULT_ID picks default */ + struct timeval *timeout /* NULL picks default */ +) +{ +RpcUdpClnt clp; +enum clnt_stat stat; + + stat = rpcUdpClntCreate( + psrvr, + prog, + vers, + uid, + gid, + &clp); + + if ( RPC_SUCCESS != stat ) + return stat; + + stat = rpcUdpClntCall( + clp, + proc, + xargs, pargs, + xres, pres, + timeout); + + rpcUdpClntDestroy(clp); + + return stat; +} + +/* linked list primitives */ +static void +nodeXtract(ListNode n) +{ + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + n->next = n->prev = 0; +} + +static void +nodeAppend(ListNode l, ListNode n) +{ + if ( (n->next = l->next) ) + n->next->prev = n; + l->next = n; + n->prev = l; + +} + +/* this code does the work */ +static void +rpcio_daemon(rtems_task_argument arg) +{ +rtems_status_code stat; +RpcUdpXact xact; +RpcUdpServer srv; +rtems_interval next_retrans, then, unow; +long now; /* need to do signed comparison with age! */ +rtems_event_set events; +ListNode newList; +rtems_unsigned32 size; +rtems_id q = 0; +ListNodeRec listHead = {0}; +unsigned long epoch = RPCIOD_EPOCH_SECS * ticksPerSec; +unsigned long max_period = RPCIOD_RETX_CAP_S * ticksPerSec; + + assert( RTEMS_SUCCESSFUL == rtems_clock_get( + RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, + &then) ); + + for (next_retrans = epoch;;) { + + if ( RTEMS_SUCCESSFUL != + (stat = rtems_event_receive( + RPCIOD_RX_EVENT | RPCIOD_TX_EVENT | RPCIOD_KILL_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + next_retrans, + &events)) ) { + ASSERT( RTEMS_TIMEOUT == stat ); + events = 0; + } + + if (events & RPCIOD_KILL_EVENT) { + int i; + +#if (DEBUG) & DEBUG_EVENTS + fprintf(stderr,"RPCIO: got KILL event\n"); +#endif + + MU_LOCK(hlock); + for (i=XACT_HASHS-1; i>=0; i--) { + if (xactHashTbl[i]) { + break; + } + } + if (i<0) { + /* prevent them from creating and enqueueing more messages */ + q=msgQ; + /* messages queued after we executed this assignment will fail */ + msgQ=0; + } + MU_UNLOCK(hlock); + if (i>=0) { + fprintf(stderr,"RPCIO There are still transactions circulating; I refuse to go away\n"); + fprintf(stderr,"(1st in slot %i)\n",i); + rtems_semaphore_release(fini); + } else { + break; + } + } + + ASSERT( RTEMS_SUCCESSFUL == rtems_clock_get( + RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, + &unow ) ); + + /* measure everything relative to then to protect against + * rollover + */ + now = unow - then; + + /* NOTE: we don't lock the hash table while we are operating + * on transactions; the paradigm is that we 'own' a particular + * transaction (and hence it's hash table slot) from the + * time the xact was put into the message queue until we + * wake up the requestor. + */ + + if (RPCIOD_RX_EVENT & events) { + +#if (DEBUG) & DEBUG_EVENTS + fprintf(stderr,"RPCIO: got RX event\n"); +#endif + + while ((xact=sockRcv())) { + + /* extract from the retransmission list */ + nodeXtract(&xact->node); + + /* change the ID - there might already be + * a retransmission on the way. When it's + * reply arrives we must not find it's ID + * in the hashtable + */ + xact->obuf.xid += XACT_HASHS; + + xact->status.re_status = RPC_SUCCESS; + + /* calculate roundtrip ticks */ + xact->trip = now - xact->trip; + + srv = xact->server; + + /* adjust the server's retry period */ + { + register TimeoutT rtry = srv->retry_period; + register TimeoutT trip = xact->trip; + + ASSERT( trip >= 0 ); + + if ( 0==trip ) + trip = 1; + + /* retry_new = 0.75*retry_old + 0.25 * 8 * roundrip */ + rtry = (3*rtry + (trip << 3)) >> 2; + + if ( rtry > max_period ) + rtry = max_period; + + srv->retry_period = rtry; + } + + /* wakeup requestor */ + rtems_event_send(xact->requestor, RTEMS_RPC_EVENT); + } + } + + if (RPCIOD_TX_EVENT & events) { + +#if (DEBUG) & DEBUG_EVENTS + fprintf(stderr,"RPCIO: got TX event\n"); +#endif + + while (RTEMS_SUCCESSFUL == rtems_message_queue_receive( + msgQ, + &xact, + &size, + RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT)) { + /* put to the head of timeout q */ + nodeAppend(&listHead, &xact->node); + + xact->age = now; + xact->trip = FIRST_ATTEMPT; + } + } + + + /* work the timeout q */ + newList = 0; + for ( xact=(RpcUdpXact)listHead.next; + xact && xact->age <= now; + xact=(RpcUdpXact)listHead.next ) { + + /* extract from the list */ + nodeXtract(&xact->node); + + srv = xact->server; + + if (xact->tolive < 0) { + /* this one timed out */ + xact->status.re_errno = ETIMEDOUT; + xact->status.re_status = RPC_TIMEDOUT; + + srv->timeouts++; + +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr,"RPCIO XACT timed out; waking up requestor\n"); +#endif + if ( rtems_event_send(xact->requestor, RTEMS_RPC_EVENT) ) { + rtems_panic("RPCIO PANIC file %s line: %i, requestor id was 0x%08x", + __FILE__, + __LINE__, + xact->requestor); + } + + } else { + int len; + + len = (int)XDR_GETPOS(&xact->xdrs); + +#ifdef MBUF_TX + xact->refcnt = 1; /* sendto itself */ +#endif + if ( len != SENDTO( ourSock, + xact->obuf.buf, + len, + 0, + (struct sockaddr*) &srv->addr, + sizeof(srv->addr) +#ifdef MBUF_TX + , xact, + paranoia_free, + paranoia_ref +#endif + ) ) { + + xact->status.re_errno = errno; + xact->status.re_status = RPC_CANTSEND; + srv->errors++; + + /* wakeup requestor */ + fprintf(stderr,"RPCIO: SEND failure\n"); + ASSERT( RTEMS_SUCCESSFUL == + rtems_event_send(xact->requestor, RTEMS_RPC_EVENT) ); + + } else { + /* send successful; calculate retransmission time + * and enqueue to temporary list + */ + if (FIRST_ATTEMPT != xact->trip) { +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr, + "timed out; tolive is %i (ticks), retry period is %i (ticks)\n", + xact->tolive, + srv->retry_period); +#endif + /* this is a real retry; we backup + * the server's retry interval + */ + if ( srv->retry_period < max_period ) { + + /* If multiple transactions for this server + * fail (e.g. because it died) this will + * back-off very agressively (doubling + * the retransmission period for every + * timed out transaction up to the CAP limit) + * which is desirable - single packet failure + * is treated more gracefully by this algorithm. + */ + + srv->retry_period<<=1; +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr, + "adjusted to; retry period %i\n", + srv->retry_period); +#endif + } else { + /* never wait longer than RPCIOD_RETX_CAP_S seconds */ + fprintf(stderr, + "RPCIO: server '%s' not responding - still trying\n", + srv->name); + } + if ( 0 == ++srv->retrans % 1000) { + fprintf(stderr, + "RPCIO - statistics: already %li retries to server %s\n", + srv->retrans, + srv->name); + } + } else { + srv->requests++; + } + xact->trip = now; + xact->age = now + srv->retry_period; + xact->tolive -= srv->retry_period; + /* enqueue to the list of newly sent transactions */ + xact->node.next = newList; + newList = &xact->node; +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr, + "XACT (0x%08x) age is 0x%x, now: 0x%x\n", + xact, + xact->age, + now); +#endif + } + } + } + + /* insert the newly sent transactions into the + * sorted retransmission list + */ + for (; (xact = (RpcUdpXact)newList); ) { + register ListNode p,n; + newList = newList->next; + for ( p=&listHead; (n=p->next) && xact->age > ((RpcUdpXact)n)->age; p=n ) + /* nothing else to do */; + nodeAppend(p, &xact->node); + } + + if (now > epoch) { + /* every now and then, readjust the epoch */ + register ListNode n; + then += now; + for (n=listHead.next; n; n=n->next) { + /* readjust outstanding time intervals subject to the + * condition that the 'absolute' time must remain + * the same. 'age' and 'trip' are measured with + * respect to 'then' - hence: + * + * abs_age == old_age + old_then == new_age + new_then + * + * ==> new_age = old_age + old_then - new_then == old_age - 'now' + */ + ((RpcUdpXact)n)->age -= now; + ((RpcUdpXact)n)->trip -= now; +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr, + "readjusted XACT (0x%08x); age is 0x%x, trip: 0x%x now: 0x%x\n", + (RpcUdpXact)n, + ((RpcUdpXact)n)->trip, + ((RpcUdpXact)n)->age, + now); +#endif + } + now = 0; + } + + next_retrans = listHead.next ? + ((RpcUdpXact)listHead.next)->age - now : + epoch; /* make sure we don't miss updating the epoch */ +#if (DEBUG) & DEBUG_TIMEOUT + fprintf(stderr,"RPCIO: next timeout is %x\n",next_retrans); +#endif + } + /* close our socket; shut down the receiver */ + close(ourSock); + +#if 0 /* if we get here, no transactions exist, hence there can be none + * in the queue whatsoever + */ + /* flush the message queue */ + while (RTEMS_SUCCESSFUL == rtems_message_queue_receive( + q, + &xact, + &size, + RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT)) { + /* TODO enque xact */ + } + + /* flush all outstanding transactions */ + + for (xact=((RpcUdpXact)listHead.next); xact; xact=((RpcUdpXact)xact->node.next)) { + xact->status.re_status = RPC_TIMEDOUT; + rtems_event_send(xact->requestor, RTEMS_RPC_EVENT); + } +#endif + + rtems_message_queue_delete(q); + + MU_DESTROY(hlock); + + fprintf(stderr,"RPC daemon exited...\n"); + + rtems_semaphore_release(fini); + rtems_task_suspend(RTEMS_SELF); +} + + +/* support for transaction 'pools'. A number of XACT objects + * is always kept around. The initial number is 0 but it + * is allowed to grow up to a maximum. + * If the need grows beyond the maximum, behavior depends: + * Users can either block until a transaction becomes available, + * they can create a new XACT on the fly or get an error + * if no free XACT is available from the pool. + */ + +RpcUdpXactPool +rpcUdpXactPoolCreate( + int prog, int version, + int xactsize, int poolsize) +{ +RpcUdpXactPool rval = MY_MALLOC(sizeof(*rval)); + + ASSERT( rval && + RTEMS_SUCCESSFUL == rtems_message_queue_create( + rtems_build_name('R','P','C','p'), + poolsize, + sizeof(RpcUdpXact), + RTEMS_DEFAULT_ATTRIBUTES, + &rval->box) ); + rval->prog = prog; + rval->version = version; + rval->xactSize = xactsize; + return rval; +} + +void +rpcUdpXactPoolDestroy(RpcUdpXactPool pool) +{ +RpcUdpXact xact; + + while ((xact = rpcUdpXactPoolGet(pool, XactGetFail))) { + rpcUdpXactDestroy(xact); + } + rtems_message_queue_delete(pool->box); + MY_FREE(pool); +} + +RpcUdpXact +rpcUdpXactPoolGet(RpcUdpXactPool pool, XactPoolGetMode mode) +{ +RpcUdpXact xact = 0; +rtems_unsigned32 size; + + if (RTEMS_SUCCESSFUL != rtems_message_queue_receive( + pool->box, + &xact, + &size, + XactGetWait == mode ? + RTEMS_WAIT : RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT)) { + + /* nothing found in box; should we create a new one ? */ + + xact = (XactGetCreate == mode) ? + rpcUdpXactCreate( + pool->prog, + pool->version, + pool->xactSize) : 0 ; + if (xact) + xact->pool = pool; + + } + return xact; +} + +void +rpcUdpXactPoolPut(RpcUdpXact xact) +{ +RpcUdpXactPool pool; + ASSERT( pool=xact->pool ); + if (RTEMS_SUCCESSFUL != rtems_message_queue_send( + pool->box, + &xact, + sizeof(xact))) + rpcUdpXactDestroy(xact); +} + +#ifdef MBUF_RX + +/* WORKAROUND: include sys/mbuf.h (or other bsdnet headers) only + * _after_ using malloc()/free() & friends because + * the RTEMS/BSDNET headers redefine those :-( + */ + +#define KERNEL +#include + +ssize_t +recv_mbuf_from(int s, struct mbuf **ppm, long len, struct sockaddr *fromaddr, int *fromlen); + +static void +bufFree(struct mbuf **m) +{ + if (*m) { + rtems_bsdnet_semaphore_obtain(); + m_freem(*m); + rtems_bsdnet_semaphore_release(); + *m = 0; + } +} +#endif + +#ifdef MBUF_TX +static void +paranoia_free(caddr_t closure, u_int size) +{ +#if (DEBUG) +RpcUdpXact xact = (RpcUdpXact)closure; +int len = (int)XDR_GETPOS(&xact->xdrs); + + ASSERT( --xact->refcnt >= 0 && size == len ); +#endif +} + +static void +paranoia_ref (caddr_t closure, u_int size) +{ +#if (DEBUG) +RpcUdpXact xact = (RpcUdpXact)closure; +int len = (int)XDR_GETPOS(&xact->xdrs); + ASSERT( size == len ); + xact->refcnt++; +#endif +} +#endif + +/* receive from a socket and find + * the transaction corresponding to the + * transaction ID received in the server + * reply. + * + * The semantics of the 'pibuf' pointer are + * as follows: + * + * MBUF_RX: + * + */ + +#define RPCIOD_RXBUFSZ UDPMSGSIZE + +static RpcUdpXact +sockRcv(void) +{ +int len,i; +u_long xid; +struct sockaddr_in fromAddr; +int fromLen = sizeof(fromAddr); +RxBuf ibuf = 0; +RpcUdpXact xact = 0; + + do { + + /* rcv_mbuf() and recvfrom() differ in that the + * former allocates buffers and passes them back + * to us whereas the latter requires us to provide + * buffer space. + * Hence, in the first case whe have to make sure + * no old buffer is leaked - in the second case, + * we might well re-use an old buffer but must + * make sure we have one allocated + */ +#ifdef MBUF_RX + if (ibuf) + bufFree(&ibuf); + + len = recv_mbuf_from( + ourSock, + &ibuf, + RPCIOD_RXBUFSZ, + (struct sockaddr*)&fromAddr, + &fromLen); +#else + if ( !ibuf ) + ibuf = (RpcBuf)MY_MALLOC(RPCIOD_RXBUFSZ); + if ( !ibuf ) + goto cleanup; /* no memory - drop this message */ + + len = recvfrom(ourSock, + ibuf->buf, + RPCIOD_RXBUFSZ, + 0, + (struct sockaddr*)&fromAddr, + &fromLen); +#endif + + if (len <= 0) { + if (EAGAIN != errno) + fprintf(stderr,"RECV failed: %s\n",strerror(errno)); + goto cleanup; + } + +#if (DEBUG) & DEBUG_PACKLOSS + if ( (unsigned)rand() < DEBUG_PACKLOSS_FRACT ) { + /* lose packets once in a while */ + static int xxx = 0; + if ( ++xxx % 16 == 0 ) + fprintf(stderr,"DEBUG: dropped %i packets, so far...\n",xxx); + if ( ibuf ) + bufFree( &ibuf ); + continue; + } +#endif + + i = (xid=XID(ibuf)) & XACT_HASH_MSK; + + if ( !(xact=xactHashTbl[i]) || + xact->obuf.xid != xid || + xact->server->addr.sin_addr.s_addr != fromAddr.sin_addr.s_addr || + xact->server->addr.sin_port != fromAddr.sin_port ) { + + if (xact) { + if (xact->server->addr.sin_addr.s_addr == fromAddr.sin_addr.s_addr && + xact->server->addr.sin_port == fromAddr.sin_port && + ( xact->obuf.xid == xid + XACT_HASHS || + xact->obuf.xid == xid + 2*XACT_HASHS ) + ) { +#ifndef DEBUG /* don't complain if it's just a late arrival of a retry */ + fprintf(stderr,"RPCIO - FYI sockRcv(): dropping late/redundant retry answer\n"); +#endif + } else { + fprintf(stderr,"RPCIO WARNING sockRcv(): transaction mismatch\n"); + fprintf(stderr,"xact: xid 0x%08lx -- got 0x%08lx\n", + xact->obuf.xid, xid); + fprintf(stderr,"xact: addr 0x%08lx -- got 0x%08lx\n", + xact->server->addr.sin_addr.s_addr, + fromAddr.sin_addr.s_addr); + fprintf(stderr,"xact: port 0x%08x -- got 0x%08x\n", + xact->server->addr.sin_port, + fromAddr.sin_port); + } + } else { + fprintf(stderr, + "RPCIO WARNING sockRcv(): got xid 0x%08lx but its slot is empty\n", + xid); + } + /* forget about this one and try again */ + xact = 0; + } + + } while ( !xact ); + + xact->ibuf = ibuf; +#ifndef MBUF_RX + xact->ibufsize = RPCIOD_RXBUFSZ; +#endif + + return xact; + +cleanup: + + bufFree(&ibuf); + + return 0; +} + + +#include +/* double check the event configuration; should probably globally + * manage system events!! + * We do this at the end of the file for the same reason we had + * included mbuf.h only a couple of lines above - see comment up + * there... + */ +#if RTEMS_RPC_EVENT & SOSLEEP_EVENT & SBWAIT_EVENT & NETISR_EVENTS +#error ILLEGAL EVENT CONFIGURATION +#endif diff --git a/rtemsNfs/src/rpcio.h b/rtemsNfs/src/rpcio.h new file mode 100644 index 0000000..922bc0d --- /dev/null +++ b/rtemsNfs/src/rpcio.h @@ -0,0 +1,205 @@ +#ifndef RPCIO_H +#define RPCIO_H +/* $Id$ */ + +/* A multihreaded RPC/UDP multiplexor */ + +/* Author: Till Straumann, , 2002 */ + +/* + * Copyright 2002, Stanford University and + * Till Straumann + * + * Stanford Notice + * *************** + * + * Acknowledgement of sponsorship + * * * * * * * * * * * * * * * * * + * This software was produced by the Stanford Linear Accelerator Center, + * Stanford University, under Contract DE-AC03-76SFO0515 with the Department + * of Energy. + * + * Government disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, + * or assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately + * owned rights. + * + * Stanford disclaimer of liability + * - - - - - - - - - - - - - - - - - + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * This product is subject to the EPICS open license + * - - - - - - - - - - - - - - - - - - - - - - - - - + * Consult the LICENSE file or http://www.aps.anl.gov/epics/license/open.php + * for more information. + * + * Maintenance of notice + * - - - - - - - - - - - + * In the interest of clarity regarding the origin and status of this + * software, Stanford University requests that any recipient of it maintain + * this notice affixed to any distribution by the recipient that contains a + * copy or derivative of this software. + */ + + +#ifdef __rtems +#include +#endif + +#include +#include +#include +#include +#include + +typedef struct RpcUdpServerRec_ *RpcUdpServer; +typedef struct RpcUdpXactRec_ *RpcUdpXact; + +typedef RpcUdpXact RpcUdpClnt; + +#define RPCIOD_DEFAULT_ID 0xdef10000 + +int +rpcUdpInit(void); + +enum clnt_stat +rpcUdpServerCreate( + struct sockaddr_in *paddr, + int prog, + int vers, + u_long uid, /* RPCIO_DEFAULT_ID picks default */ + u_long gid, /* RPCIO_DEFAULT_ID picks default */ + RpcUdpServer *pclnt /* new server is returned here */ + ); + + +void +rpcUdpServerDestroy(RpcUdpServer s); + +/* Dump statistics to a file (stdout if NULL); + * returns 0 for convenience + */ +int +rpcUdpStats(FILE *f); + +enum clnt_stat +rpcUdpClntCreate( + struct sockaddr_in *psaddr, + int prog, + int vers, + u_long uid, /* RPCIO_DEFAULT_ID picks default */ + u_long gid, /* RPCIO_DEFAULT_ID picks default */ + RpcUdpClnt *pclnt /* new client is returned here */ + ); + +void +RpcUdpClntDestroy(RpcUdpClnt clnt); + +/* mute compiler warnings */ +typedef void *XdrProcT; +typedef void *CaddrT; + +enum clnt_stat +rpcUdpClntCall( + RpcUdpClnt clnt, + u_long proc, + XdrProcT xargs, + CaddrT pargs, + XdrProcT xres, + CaddrT pres, + struct timeval *timeout /* optional timeout; maybe NULL to pick default */ + ); + +RpcUdpXact +rpcUdpXactCreate( + u_long program, + u_long version, + u_long size + ); + +void +rpcUdpXactDestroy( + RpcUdpXact xact + ); + +/* send a transaction */ +enum clnt_stat +rpcUdpSend( + RpcUdpXact xact, + RpcUdpServer srvr, + struct timeval *timeout, /* maybe NULL to pick default */ + u_long proc, + xdrproc_t xres, + caddr_t pres, + xdrproc_t xargs, + caddr_t pargs, + ... /* 0 terminated xdrproc/pobj additional argument list */ + ); + +/* wait for a transaction to complete */ +enum clnt_stat +rpcUdpRcv(RpcUdpXact xact); + +/* a yet simpler interface */ +enum clnt_stat +rpcUdpCallRp( + struct sockaddr_in *pserver_addr, + u_long prog, + u_long vers, + u_long proc, + XdrProcT xargs, + CaddrT pargs, + XdrProcT xres, + CaddrT pres, + u_long uid, /* RPCIO_DEFAULT_ID picks default */ + u_long gid, /* RPCIO_DEFAULT_ID picks default */ + struct timeval *timeout /* NULL picks default */ +); + + +/* manage pools of transactions */ + +/* A pool of transactions. The idea is not to malloc/free them + * all the time but keep a limited number around in a 'pool'. + * Users who need a XACT may get it from the pool and put it back + * when done. + * The pool is implemented by RTEMS message queues who manage + * the required task synchronization. + * A requestor has different options if the pool is empty: + * - it can wait (block) for a XACT to become available + * - it can get an error status + * - or it can malloc an extra XACT from the heap which + * will eventually be released. + */ + +typedef struct RpcUdpXactPoolRec_ *RpcUdpXactPool; + +/* NOTE: the pool is empty initially, must get messages (in + * GetCreate mode + */ +RpcUdpXactPool +rpcUdpXactPoolCreate( + int prog, int version, + int xactsize, int poolsize); + +void +rpcUdpXactPoolDestroy(RpcUdpXactPool pool); + +typedef enum { + XactGetFail, /* call fails if no transaction available */ + XactGetWait, /* call blocks until transaction available */ + XactGetCreate /* a new transaction is allocated (and freed when put back to the pool */ +} XactPoolGetMode; + +RpcUdpXact +rpcUdpXactPoolGet(RpcUdpXactPool pool, XactPoolGetMode mode); + +void +rpcUdpXactPoolPut(RpcUdpXact xact); + +#endif diff --git a/rtemsNfs/src/rpcio.modini.c b/rtemsNfs/src/rpcio.modini.c new file mode 100644 index 0000000..7773b3d --- /dev/null +++ b/rtemsNfs/src/rpcio.modini.c @@ -0,0 +1,15 @@ +#include "librtemsNfs.h" +/* CEXP module support (magic init) */ +void +_cexpModuleInitialize(void *mod) +{ + rpcUdpInit(); +} + +int +_cexpModuleFinalize(void *mod) +{ + return rpcUdpCleanup(); +} + + diff --git a/rtemsNfs/src/sock_mbuf.c b/rtemsNfs/src/sock_mbuf.c new file mode 100644 index 0000000..70c09d6 --- /dev/null +++ b/rtemsNfs/src/sock_mbuf.c @@ -0,0 +1,279 @@ +/* + * $Id$ + * + * NOTE: + * This is derived from libnetworking/rtems/rtems_syscall.c + * + * RTEMS/libnetworking LICENSING restrictions may apply + * + * Author (modifications only): + * Copyright: 2002, Stanford University and + * Till Straumann, + * Licensing: 'LICENSE.NET' file in the RTEMS top source directory + * for more information. + */ + +/* +The RTEMS TCP/IP stack is a port of the FreeBSD TCP/IP stack. The following +copyright and licensing information applies to this code. + +This code is found under the c/src/libnetworking directory but does not +constitute the entire contents of that subdirectory. + +============================================================================= + +Copyright (c) 1980, 1983, 1988, 1993 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgment: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +- +Portions Copyright (c) 1993 by Digital Equipment Corporation. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +============================================================================= +*/ + + +#include +#include +#include + +#include +#include +#include + +#define KERNEL +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct socket *rtems_bsdnet_fdToSocket(int fd); + +/* + * Package system call argument into mbuf. + * + * (unfortunately, the original is not public) + */ +static int +sockaddrtombuf (struct mbuf **mp, const struct sockaddr *buf, int buflen) +{ +struct mbuf *m; +struct sockaddr *sa; + + if ((u_int)buflen > MLEN) + return (EINVAL); + + rtems_bsdnet_semaphore_obtain(); + m = m_get(M_WAIT, MT_SONAME); + rtems_bsdnet_semaphore_release(); + + if (m == NULL) + return (ENOBUFS); + m->m_len = buflen; + memcpy (mtod(m, caddr_t), buf, buflen); + *mp = m; + sa = mtod(m, struct sockaddr *); + sa->sa_len = buflen; + + return 0; +} + +static void +dummyproc(caddr_t ext_buf, u_int ext_size) +{ +} + +/* + * send data by simply allocating an MBUF packet + * header and pointing it to our data region. + * + * Optionally, the caller may supply 'reference' + * and 'free' procs. (The latter may call the + * user back once the networking stack has + * released the buffer). + * + * The callbacks are provided with the 'closure' + * pointer and the 'buflen' argument. + */ +ssize_t +sendto_nocpy ( + int s, + const void *buf, size_t buflen, + int flags, + const struct sockaddr *toaddr, int tolen, + void *closure, + void (*freeproc)(caddr_t, u_int), + void (*refproc)(caddr_t, u_int) +) +{ + int error; + struct socket *so; + struct mbuf *to, *m; + int ret = -1; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + + error = sockaddrtombuf (&to, toaddr, tolen); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + + MGETHDR(m, M_WAIT, MT_DATA); + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *) 0; + + m->m_flags |= M_EXT; + m->m_ext.ext_buf = closure ? closure : (void*)buf; + m->m_ext.ext_size = buflen; + /* we _must_ supply non-null procs; otherwise, + * the kernel code assumes it's a mbuf cluster + */ + m->m_ext.ext_free = freeproc ? freeproc : dummyproc; + m->m_ext.ext_ref = refproc ? refproc : dummyproc; + m->m_pkthdr.len += buflen; + m->m_len = buflen; + m->m_data = (void*)buf; + + error = sosend (so, to, NULL, m, NULL, flags); + if (error) { + if (/*auio.uio_resid != len &&*/ (error == EINTR || error == EWOULDBLOCK)) + error = 0; + } + if (error) + errno = error; + else + ret = buflen; + if (to) + m_freem(to); + rtems_bsdnet_semaphore_release (); + return (ret); +} + + +/* + * receive data in an 'mbuf chain'. + * The chain must be released once the + * data has been extracted: + * + * rtems_bsdnet_semaphore_obtain(); + * m_freem(chain); + * rtems_bsdnet_semaphore_release(); + */ +ssize_t +recv_mbuf_from(int s, struct mbuf **ppm, long len, struct sockaddr *fromaddr, int *fromlen) +{ + int ret = -1; + int error; + struct uio auio; + struct socket *so; + struct mbuf *from = NULL; + + memset(&auio, 0, sizeof(auio)); + *ppm = 0; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } +/* auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_READ; + auio.uio_offset = 0; +*/ + auio.uio_resid = len; + error = soreceive (so, &from, &auio, (struct mbuf **) ppm, + (struct mbuf **)NULL, + NULL); + if (error) { + if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) + error = 0; + } + if (error) { + errno = error; + } + else { + ret = len - auio.uio_resid; + if (fromaddr) { + len = *fromlen; + if ((len <= 0) || (from == NULL)) { + len = 0; + } + else { + if (len > from->m_len) + len = from->m_len; + memcpy (fromaddr, mtod(from, caddr_t), len); + } + *fromlen = len; + } + } + if (from) + m_freem (from); + if (error && *ppm) { + m_freem(*ppm); + *ppm = 0; + } + rtems_bsdnet_semaphore_release (); + return (ret); +} diff --git a/rtemsNfs/src/xdr_mbuf.c b/rtemsNfs/src/xdr_mbuf.c new file mode 100644 index 0000000..22f972d --- /dev/null +++ b/rtemsNfs/src/xdr_mbuf.c @@ -0,0 +1,534 @@ +/* $Id$ */ + +/* xdr_mbuf is derived from xdr_mem */ + +/* Author (mbuf specifica): Till Straumann , 10/2002 */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr_mem.c,v 1.8 1999/08/28 00:02:56 peter Exp $"; +#endif + +/* + * xdr_mbuf, XDR implementation using mbuf buffers + * + * derived from: + * + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The MBUF stream is useful for BSDNET kernel (or RTEMS for that matter) + * use. + */ + +#include +#include +#include +#include + +#include + +#define TODO + +/* TODO remove: a hack because malloc is redefined */ +#ifdef TODO +static inline void * +my_malloc(size_t i) +{ + return malloc(i); +} + +static inline void +my_free(void *p) +{ + return free(p); +} +#endif + +#define DEBUG_ASSERT (1<<0) +#define DEBUG_VERB (1<<1) + +#define DEBUG DEBUG_ASSERT + +#define KERNEL +#include + +#include + +#if DEBUG & DEBUG_VERB || defined(TODO) +#include +#endif + +static bool_t xdrmbuf_getlong_aligned(); +static bool_t xdrmbuf_putlong_aligned(); +static bool_t xdrmbuf_getlong_unaligned(); +static bool_t xdrmbuf_putlong_unaligned(); +static bool_t xdrmbuf_getbytes(); +static bool_t xdrmbuf_putbytes(); +static u_int xdrmbuf_getpos(); /* XXX w/64-bit pointers, u_int not enough! */ +static bool_t xdrmbuf_setpos(); +static int32_t *xdrmbuf_inline_aligned(); +static int32_t *xdrmbuf_inline_unaligned(); +static void xdrmbuf_destroy(); + +static struct xdr_ops xdrmbuf_ops_aligned = { + xdrmbuf_getlong_aligned, + xdrmbuf_putlong_aligned, + xdrmbuf_getbytes, + xdrmbuf_putbytes, + xdrmbuf_getpos, + xdrmbuf_setpos, + xdrmbuf_inline_aligned, + xdrmbuf_destroy +}; + +static struct xdr_ops xdrmbuf_ops_unaligned = { + xdrmbuf_getlong_unaligned, + xdrmbuf_putlong_unaligned, + xdrmbuf_getbytes, + xdrmbuf_putbytes, + xdrmbuf_getpos, + xdrmbuf_setpos, + xdrmbuf_inline_unaligned, + xdrmbuf_destroy +}; + +typedef struct MBPrivateRec_ { + struct mbuf *mchain; + struct mbuf *mcurrent; + u_int pos; /* number of bytes contained in all MUBFS ahead + * of mcurrent + */ +} MBPrivateRec, *MBPrivate; + +/* NOTE: the stream position helper 'pos' + * must be managed by the caller! + */ +static inline void +xdrmbuf_setup(XDR *xdrs, struct mbuf *m) +{ +MBPrivate mbp = (MBPrivate)xdrs->x_base; + + mbp->mcurrent = m; + xdrs->x_private = mtod(m,caddr_t); + xdrs->x_handy = m->m_len; + xdrs->x_ops = ((size_t)xdrs->x_private & (sizeof(int32_t) - 1)) + ? &xdrmbuf_ops_unaligned : &xdrmbuf_ops_aligned; +} + +static struct mbuf * +xdrmbuf_next(XDR *xdrs) +{ +struct mbuf *rval; +MBPrivate mbp = (MBPrivate)xdrs->x_base; + + if (mbp->mcurrent) { + mbp->pos += mbp->mcurrent->m_len; + rval = mbp->mcurrent->m_next; + } else { + rval = 0; + } + + if (rval) { + xdrmbuf_setup(xdrs, rval); + } +#if DEBUG & DEBUG_VERB + else { + fprintf(stderr,"xdrmbuf: end of chain\n"); + } +#endif + + return rval; +} + +/* + * The procedure xdrmbuf_create initializes a stream descriptor for a + * memory buffer. + */ +void +xdrmbuf_create(XDR *xdrs, struct mbuf *mbuf, enum xdr_op op) +{ +MBPrivate mbp; + + xdrs->x_op = op; + assert( mbp = (MBPrivate)my_malloc(sizeof(*mbp)) ); + xdrs->x_base = (caddr_t) mbp; + + mbp->mchain = mbuf; + mbp->pos = 0; + +#if DEBUG & DEBUG_VERB + { + struct mbuf *mbf; + fprintf(stderr,"Dumping chain:\n"); + for (mbf = mbuf; mbf; mbf=mbf->m_next) { + int ii; + fprintf(stderr,"MBUF------------"); + for (ii=0; iim_len; ii++) { + fprintf(stderr,"%02x ",mtod(mbf,char*)[ii]); + if (ii%16==0) + fputc('\n',stderr); + } + fputc('\n',stderr); + } + } +#endif + + xdrmbuf_setup(xdrs, mbuf); +} + +static void +xdrmbuf_destroy(XDR *xdrs) +{ +MBPrivate mbp = (MBPrivate)xdrs->x_base; +#if 0 /* leave destroying the chain to the user */ +struct mbuf *m = mbp->mchain; + + rtems_bsdnet_semaphore_obtain(); + m_freem(m); + rtems_bsdnet_semaphore_release(); +#endif + + my_free(mbp); +} + +static bool_t +xdrmbuf_getlong_aligned(register XDR *xdrs, register long *lp) +{ + while ( (signed int)(xdrs->x_handy -= sizeof(int32_t)) < 0) { + if ((xdrs->x_handy += sizeof(int32_t)) == 0) { + /* handy was 0 on entry; request a new buffer. + * Coded this way, so the most frequently executed + * path needs only one comparison... + */ + if (!xdrmbuf_next(xdrs)) + return FALSE; + } else { + /* uh-oh an aligned long spread over two MBUFS ?? + * let the unaligned handler deal with this rare + * situation. + */ + return xdrmbuf_getlong_unaligned(xdrs,lp); + } + } + *lp = ntohl(*(int32_t *)(xdrs->x_private)); + xdrs->x_private += sizeof(int32_t); +#if DEBUG & DEBUG_VERB + fprintf(stderr,"Got aligned long %x\n",*lp); +#endif + return (TRUE); +} + +static bool_t +xdrmbuf_putlong_aligned(xdrs, lp) + register XDR *xdrs; + long *lp; +{ +fprintf(stderr,"TODO: xdrmbuf_putlong_aligned() is unimplemented\n"); + return FALSE; +#if 0 + if ((xdrs->x_handy -= sizeof(int32_t)) < 0) + return (FALSE); + *(int32_t *)xdrs->x_private = htonl(*lp); + xdrs->x_private += sizeof(int32_t); + return (TRUE); +#endif +} + +static bool_t +xdrmbuf_getlong_unaligned(xdrs, lp) + register XDR *xdrs; + long *lp; +{ +union { + int32_t l; + char c[sizeof(int32_t)]; +} u; + +register int i,j; +register char *cp,*sp; + + i = xdrs->x_handy - sizeof(int32_t); + + /* handle the most common case first */ + if ( i >= 0 ) { + + xdrs->x_handy = i; + sp = (char*)xdrs->x_private; + xdrs->x_private = sp + sizeof(int32_t); + +#ifdef CANDO_UNALIGNED + { + *lp = ntohl(*(int32_t *)sp); +# if DEBUG & DEBUG_VERB + fprintf(stderr,"Got unaligned long %x (%i remaining)\n",*lp, xdrs->x_handy); +# endif + return TRUE; + } +#else /* machine can't do unaligned access */ + { + u.c[0] = *sp; + u.c[1] = *++sp; + u.c[2] = *++sp; + u.c[3] = *++sp; + + goto done; + } +#endif /* CANDO_UNALIGNED */ + } + + /* here the messy 'crossing buffers' business starts */ + + + j = sizeof(int32_t); + + cp = u.c-1; + + /* NOTE: on entry to this section, handy < j holds */ + do { + sp = ((char*)xdrs->x_private)-1; + + if ( (i=xdrs->x_handy) >= j ) { + /* more data in the buffer than we need: + * copy everything we need and goto 'done' + */ + xdrs->x_handy = i-j; + do { + *++cp = *++sp; + } while (--j > 0); + xdrs->x_private = (caddr_t)++sp; + + goto done; + + } else { + /* not enough data - copy as much as possible + * then get retrieve the next MBUF and start + * over + */ + j-=i; + while (i--) + *++cp = *++sp; + if (!xdrmbuf_next(xdrs)) + return FALSE; +#if DEBUG & DEBUG_VERB + fprintf(stderr,"getlong_unaligned: crossed mbuf boundary\n"); +#endif + } + } while (j > 0); + +done: + + *lp = ntohl(u.l); + +#if DEBUG & DEBUG_VERB + fprintf(stderr,"Got unaligned long %x (%i remaining)\n",*lp, xdrs->x_handy); +#endif + return (TRUE); +} + +static bool_t +xdrmbuf_putlong_unaligned(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + fprintf(stderr,"TODO: xdrmbuf_putlong_unaligned() is unimplemented\n"); + return FALSE; +#if 0 + { + int32_t l; + + if ((xdrs->x_handy -= sizeof(int32_t)) < 0) + return (FALSE); + l = htonl(*lp); + memcpy(xdrs->x_private, &l, sizeof(int32_t)); + xdrs->x_private += sizeof(int32_t); + return (TRUE); + } +#endif +} + +static bool_t +xdrmbuf_getbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register u_int len; +{ +#if DEBUG & DEBUG_VERB +int olen=len,bufs=0; +#endif + +#if DEBUG & DEBUG_VERB + fprintf(stderr,"wanting %i bytes (have %i)\n",olen,xdrs->x_handy); +#endif + + while (len>0) { + if (xdrs->x_handy >= len) { + memcpy(addr, xdrs->x_private, len); + xdrs->x_private += len; + xdrs->x_handy -= len; +#if 0 /* save a couple of instructions */ + len = 0; +#else + goto done; +#endif + } else { + if (xdrs->x_handy > 0) { + memcpy(addr, xdrs->x_private, xdrs->x_handy); + len -= xdrs->x_handy; + addr += xdrs->x_handy; + } + if (!xdrmbuf_next(xdrs)) + return FALSE; +#if DEBUG & DEBUG_VERB + bufs++; +#endif + } + } +done: +#if DEBUG & DEBUG_VERB + fprintf(stderr,"Got %i bytes (out of %i mbufs)\n",olen,bufs); +#endif + return (TRUE); +} + +static bool_t +xdrmbuf_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register u_int len; +{ + + fprintf(stderr,"TODO: xdrmbuf_putbytes() is unimplemented\n"); + return FALSE; +#if 0 + if ((xdrs->x_handy -= len) < 0) + return (FALSE); + memcpy(xdrs->x_private, addr, len); + xdrs->x_private += len; + return (TRUE); +#endif +} + +static u_int +xdrmbuf_getpos(xdrs) + register XDR *xdrs; +{ +#if 1 +MBPrivate mbp = (MBPrivate)xdrs->x_base; +struct mbuf *m = mbp->mcurrent; +u_int rval = mbp->pos; + + if (m) { + rval += (u_long)xdrs->x_private - mtod(m, u_long); + } +#else +struct mbuf *m; +u_int rval = 0; +MBPrivate mbp = (MBPrivate)xdrs->x_base; + + for ( m = mbp->mchain; m && m != mbp->mcurrent; m = m->m_next ) + rval += m->m_len; + if (m) { + rval += (u_long)xdrs->x_private - mtod(m, u_long); + } + +#endif + return rval; +} + +static bool_t +xdrmbuf_setpos(xdrs, pos) + register XDR *xdrs; + u_int pos; +{ +struct mbuf *m; +MBPrivate mbp = (MBPrivate)xdrs->x_base; + + if (pos >= mbp->pos) { + pos -= mbp->pos; + m = mbp->mcurrent; + } else { + m = mbp->mchain; + mbp->pos = 0; + } + + while ( m && pos >= m->m_len ) { + pos -= m->m_len; + mbp->pos += m->m_len; + m = m->m_next; + } + + if (m) { + xdrmbuf_setup(xdrs, m); + xdrs->x_private += pos; + return TRUE; + } + + return 0 == pos ? TRUE : FALSE; +} + +static int32_t * +xdrmbuf_inline_aligned(xdrs, len) + register XDR *xdrs; + int len; +{ +int32_t *buf = 0; + + if (xdrs->x_handy == 0 && !xdrmbuf_next(xdrs)) + return 0; + + if (xdrs->x_handy >= len) { + xdrs->x_handy -= len; + buf = (int32_t *) xdrs->x_private; + xdrs->x_private += len; +#if DEBUG & DEBUG_VERB + fprintf(stderr,"Got %i aligned inline bytes at %x\n", len, buf); +#endif + } +#if DEBUG & DEBUG_VERB + else { + fprintf(stderr,"Skipped %i aligned inline bytes\n",len); + } +#endif + return (buf); +} + +static int32_t * +xdrmbuf_inline_unaligned(xdrs, len) + register XDR *xdrs; + int len; +{ + return (0); +} -- cgit v1.2.3