summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/nfsclient/src
diff options
context:
space:
mode:
authorVijay Kumar Banerjee <vijay@rtems.org>2021-02-24 19:08:51 -0700
committerVijay Kumar Banerjee <vijay@rtems.org>2021-04-07 16:15:38 -0600
commit6692e03e9d1b8fae6526b828460c96b3db18d1d5 (patch)
tree4927275a0dec414792a152b5301e73e09716948e /cpukit/libfs/src/nfsclient/src
parentcpukit: remove pppd (diff)
downloadrtems-6692e03e9d1b8fae6526b828460c96b3db18d1d5.tar.bz2
cpukit/libfs: Remove nfsclient
Update #3850
Diffstat (limited to '')
-rw-r--r--cpukit/libfs/src/nfsclient/src/nfs.c3203
-rw-r--r--cpukit/libfs/src/nfsclient/src/nfsclient-private.h14
-rw-r--r--cpukit/libfs/src/nfsclient/src/rpcio.c1774
-rw-r--r--cpukit/libfs/src/nfsclient/src/rpcio.h226
-rw-r--r--cpukit/libfs/src/nfsclient/src/sock_mbuf.c285
-rw-r--r--cpukit/libfs/src/nfsclient/src/xdr_mbuf.c548
6 files changed, 0 insertions, 6050 deletions
diff --git a/cpukit/libfs/src/nfsclient/src/nfs.c b/cpukit/libfs/src/nfsclient/src/nfs.c
deleted file mode 100644
index bc9a2c6246..0000000000
--- a/cpukit/libfs/src/nfsclient/src/nfs.c
+++ /dev/null
@@ -1,3203 +0,0 @@
-/**
- * @file
- *
- * @ingroup RTEMSFileSystemNFS
- *
- * @brief NFS Client Implementation for RTEMS
- *
- * Hooks Into the RTEMS NFS Filesystem
- */
-
-/*
- * Author: Till Straumann <strauman@slac.stanford.edu>, 2002
- *
- * Hacked on by others.
- *
- * Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
- *
- * Authorship
- * ----------
- * This software (NFS-2 client implementation for RTEMS) was created by
- * Till Straumann <strauman@slac.stanford.edu>, 2002-2007,
- * Stanford Linear Accelerator Center, Stanford University.
- *
- * Acknowledgement of sponsorship
- * ------------------------------
- * The NFS-2 client implementation for RTEMS 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.
- *
- * Stanford disclaimer of copyright
- * --------------------------------
- * Stanford University, owner of the copyright, hereby disclaims its
- * copyright and all other rights in this software. Hence, anyone may
- * freely use it for any purpose without restriction.
- *
- * Maintenance of notices
- * ----------------------
- * In the interest of clarity regarding the origin and status of this
- * SLAC software, this and all the preceding Stanford University notices
- * are to remain affixed to any copy or derivative of this software made
- * or distributed by the recipient and are to be affixed to any copy of
- * software made or distributed by the recipient that contains a copy or
- * derivative of this software.
- *
- * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <rtems.h>
-#include <rtems/libio.h>
-#include <rtems/libio_.h>
-#include <rtems/seterr.h>
-#include <rtems/thread.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "../proto/nfs_prot.h"
-#include "../proto/mount_prot.h"
-
-#include "rpcio.h"
-#include "librtemsNfs.h"
-
-/* Configurable parameters */
-
-/* Estimated average length of a filename (including terminating 0).
- * This was calculated by doing
- *
- * find <some root> -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*/
-
-/*
- * The 'st_blksize' (stat(2)) value this nfs
- * client should report. If set to zero then the server's fattr data
- * is passed throught which is not necessary optimal.
- * Newlib's stdio uses 'st_blksize' (if built with HAVE_BLKSIZE defined)
- * to size the default buffer.
- * Due to the overhead of NFS it is probably better to use the maximum
- * size of an NFS read request (8k) rather than the optimal block
- * size on the server.
- * This value can be overridden at run-time by setting the global
- * variable 'nfsStBlksize'.
- * Thanks to Steven Johnson <sjohnson@sakuraindustries.com> for helping
- * working on this issue.
- */
-#define DEFAULT_NFS_ST_BLKSIZE NFS_MAXDATA
-
-/* 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. [Later versions of RTEMS have fixed this;
- * nfsInit() issues a warning if you run a version with 'short st_ino'.]
- *
- * 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, \
- (((rtems_device_minor_number)((node)->nfs->id))<<16) | (((rtems_device_minor_number)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, \
- (((rtems_device_minor_number)((node)->nfs->id))<<16) | (SERP_ATTR((node)).fsid & (((rtems_device_minor_number)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 LOCK(s) rtems_recursive_mutex_lock(&(s))
-
-#define UNLOCK(s) rtems_recursive_mutex_unlock(&(s))
-
-RTEMS_INTERRUPT_LOCK_DEFINE(static, nfs_global_lock, "NFS")
-
-#define NFS_GLOBAL_ACQUIRE(lock_context) \
- rtems_interrupt_lock_acquire(&nfs_global_lock, lock_context)
-
-#define NFS_GLOBAL_RELEASE(lock_context) \
- rtems_interrupt_lock_release(&nfs_global_lock, lock_context)
-
-static inline char *
-nfs_dupname(const char *name, size_t namelen)
-{
- char *dupname = malloc(namelen + 1);
-
- if (dupname != NULL) {
- memcpy(dupname, name, namelen);
- dupname [namelen] = '\0';
- } else {
- errno = ENOMEM;
- }
-
- return dupname;
-}
-
-/*****************************************
- 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;
-
-/* Read 'readlink' results into a 'strbuf'.
- * This is convenient as it avoids
- * one extra step of copying / length
- * 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;
-#ifdef DT_UNKNOWN
- pde->d_type = DT_UNKNOWN;
-#endif
- 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, (void*)&dip, 0 /* size */, (xdrproc_t)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 {
- uint32_t offset;
- uint32_t count;
- uint32_t totalcount;
- } readarg;
- struct {
- uint32_t beginoffset;
- uint32_t offset;
- uint32_t totalcount;
- struct {
- uint32_t 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;
- uint32_t 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 uint32_t TimeStamp;
-
-static inline TimeStamp
-nowSeconds(void)
-{
- rtems_interval rval;
- rtems_clock_get_seconds_since_epoch( &rval );
- 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.
- */
- volatile int nodesInUse;
-#if DEBUG & DEBUG_COUNT_NODES
- /* statistics; how many 'NfsNode.str'
- * strings are currently allocated.
- */
- volatile 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 ssize_t nfs_readlink_with_node(
- NfsNode node,
- char *buf,
- 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 const struct _rtems_filesystem_operations_table nfs_fs_ops;
-static const struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers;
-static const struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers;
-static const struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers;
-static 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);
-
-/*****************************************
- Global Variables
- *****************************************/
-
-/* These are (except for MAXNAMLEN/MAXPATHLEN) copied from IMFS */
-
-static const 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_recursive_mutex llock;
- /* A lock for protecting misc
- * stuff within the driver.
- * The lock must only be held
- * for short periods of time.
- */
- rtems_recursive_mutex 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;
-
- /* 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
- */
- RpcUdpXactPool smallPool;
- RpcUdpXactPool bigPool;
-} nfsGlob = {RTEMS_RECURSIVE_MUTEX_INITIALIZER("NFS List"), RTEMS_RECURSIVE_MUTEX_INITIALIZER("NFS Misc"), 0xffffffff, 0, 0, 0, NULL, NULL};
-
-/*
- * Global variable to tune the 'st_blksize' (stat(2)) value this nfs
- * client should report.
- * size on the server.
- */
-#ifndef DEFAULT_NFS_ST_BLKSIZE
-#define DEFAULT_NFS_ST_BLKSIZE NFS_MAXDATA
-#endif
-int nfsStBlksize = DEFAULT_NFS_ST_BLKSIZE;
-
-
-/*****************************************
- Implementation
- *****************************************/
-
-static int nfsEvaluateStatus(nfsstat nfsStatus)
-{
- static const uint8_t nfsStatusToErrno [71] = {
- [NFS_OK] = 0,
- [NFSERR_PERM] = EPERM,
- [NFSERR_NOENT] = ENOENT,
- [3] = EIO,
- [4] = EIO,
- [NFSERR_IO] = EIO,
- [NFSERR_NXIO] = ENXIO,
- [7] = EIO,
- [8] = EIO,
- [9] = EIO,
- [10] = EIO,
- [11] = EIO,
- [12] = EIO,
- [NFSERR_ACCES] = EACCES,
- [14] = EIO,
- [15] = EIO,
- [16] = EIO,
- [NFSERR_EXIST] = EEXIST,
- [18] = EIO,
- [NFSERR_NODEV] = ENODEV,
- [NFSERR_NOTDIR] = ENOTDIR,
- [NFSERR_ISDIR] = EISDIR,
- [22] = EIO,
- [24] = EIO,
- [25] = EIO,
- [26] = EIO,
- [27] = EIO,
- [NFSERR_FBIG] = EFBIG,
- [NFSERR_NOSPC] = ENOSPC,
- [29] = EIO,
- [NFSERR_ROFS] = EROFS,
- [31] = EIO,
- [32] = EIO,
- [34] = EIO,
- [35] = EIO,
- [36] = EIO,
- [37] = EIO,
- [38] = EIO,
- [39] = EIO,
- [40] = EIO,
- [41] = EIO,
- [42] = EIO,
- [44] = EIO,
- [45] = EIO,
- [46] = EIO,
- [47] = EIO,
- [48] = EIO,
- [49] = EIO,
- [50] = EIO,
- [51] = EIO,
- [52] = EIO,
- [54] = EIO,
- [55] = EIO,
- [56] = EIO,
- [57] = EIO,
- [58] = EIO,
- [59] = EIO,
- [60] = EIO,
- [61] = EIO,
- [62] = EIO,
- [NFSERR_NAMETOOLONG] = ENAMETOOLONG,
- [64] = EIO,
- [65] = EIO,
- [NFSERR_NOTEMPTY] = ENOTEMPTY,
- [67] = EIO,
- [68] = EIO,
- [NFSERR_DQUOT] = EDQUOT,
- [NFSERR_STALE] = ESTALE
- };
-
- size_t idx = (size_t) nfsStatus;
- int eno = EIO;
- int rv = 0;
-
- if (idx < sizeof(nfsStatusToErrno) / sizeof(nfsStatusToErrno [0])) {
- eno = nfsStatusToErrno [idx];
- }
-
- if (eno != 0) {
- errno = eno;
- rv = -1;
- }
-
- return rv;
-}
-
-/* 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, fhandle *fh)
-{
-NfsNode rval = malloc(sizeof(*rval));
-rtems_interrupt_lock_context lock_context;
-
-#if DEBUG & DEBUG_TRACK_NODES
- fprintf(stderr,"NFS: creating a node\n");
-#endif
-
- if (rval) {
- if (fh)
- memcpy( &SERP_FILE(rval), fh, sizeof(*fh) );
- NFS_GLOBAL_ACQUIRE(&lock_context);
- nfs->nodesInUse++;
- NFS_GLOBAL_RELEASE(&lock_context);
- rval->nfs = nfs;
- rval->str = 0;
- } else {
- errno = ENOMEM;
- }
-
- return rval;
-}
-
-/* destroy a node */
-static void
-nfsNodeDestroy(NfsNode node)
-{
-rtems_interrupt_lock_context lock_context;
-
-#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
-
- NFS_GLOBAL_ACQUIRE(&lock_context);
- node->nfs->nodesInUse--;
-#if DEBUG & DEBUG_COUNT_NODES
- if (node->str)
- node->nfs->stringsInUse--;
-#endif
- NFS_GLOBAL_RELEASE(&lock_context);
-
- 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) {
- errno = ENOMEM;
- nfsNodeDestroy(rval);
- return 0;
- }
-#if DEBUG & DEBUG_COUNT_NODES
- { rtems_interrupt_lock_context lock_context;
- NFS_GLOBAL_ACQUIRE(&lock_context);
- node->nfs->stringsInUse++;
- NFS_GLOBAL_RELEASE(&lock_context);
- }
-#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).
- */
-int
-nfsInit(int smallPoolDepth, int bigPoolDepth)
-{
-static int initialised = 0;
-entry dummy;
-
- if (initialised)
- return 0;
-
- initialised = 1;
-
- fprintf(stderr,
- "RTEMS-NFS, " \
- "Till Straumann, Stanford/SLAC/SSRL 2002, " \
- "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));
- errno = ENOMEM;
- return -1;
- }
-
- if (0==smallPoolDepth)
- smallPoolDepth = 20;
- if (0==bigPoolDepth)
- bigPoolDepth = 10;
-
- rtems_recursive_mutex_init(&nfsGlob.llock, "NFSl");
- rtems_recursive_mutex_init(&nfsGlob.lock, "NFSm");
-
- /* 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((xdrproc_t)xdr_entry, &dummy);
-
- nfsGlob.smallPool = rpcUdpXactPoolCreate(
- NFS_PROGRAM,
- NFS_VERSION_2,
- CONFIG_NFS_SMALL_XACT_SIZE,
- smallPoolDepth);
- if (nfsGlob.smallPool == NULL) {
- goto cleanup;
- }
-
- nfsGlob.bigPool = rpcUdpXactPoolCreate(
- NFS_PROGRAM,
- NFS_VERSION_2,
- CONFIG_NFS_BIG_XACT_SIZE,
- bigPoolDepth);
- if (nfsGlob.bigPool == NULL) {
- goto cleanup;
- }
-
- 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");
-
- }
-
- return 0;
-
-cleanup:
-
- nfsCleanup();
- initialised = 0;
-
- return -1;
-}
-
-/* Driver cleanup code
- */
-int
-nfsCleanup(void)
-{
-int refuse;
-
- 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;
- }
-
- if (nfsGlob.smallPool != NULL) {
- rpcUdpXactPoolDestroy(nfsGlob.smallPool);
- nfsGlob.smallPool = NULL;
- }
-
- if (nfsGlob.bigPool != NULL) {
- rpcUdpXactPoolDestroy(nfsGlob.bigPool);
- nfsGlob.bigPool = NULL;
- }
-
- if (nfsGlob.nfs_major != 0xffffffff) {
- rtems_io_unregister_driver(nfsGlob.nfs_major);
- nfsGlob.nfs_major = 0xffffffff;
- }
-
- UNLOCK(nfsGlob.llock);
-
- rtems_recursive_mutex_destroy(&nfsGlob.lock);
- rtems_recursive_mutex_destroy(&nfsGlob.llock);
-
- 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 = nfsGlob.bigPool; break;
- default: pool = nfsGlob.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)
-{
- int rv = 0;
-
- if (force
-#ifdef CONFIG_ATTR_LIFETIME
- || (nowSeconds() - node->age > CONFIG_ATTR_LIFETIME)
-#endif
- ) {
- rv = nfscall(
- node->nfs->server,
- NFSPROC_GETATTR,
- (xdrproc_t) xdr_nfs_fh, &SERP_FILE(node),
- (xdrproc_t) xdr_attrstat, &node->serporid
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(node->serporid.status);
-
- if (rv == 0) {
- node->age = nowSeconds();
- }
- }
- }
-
- return rv;
-}
-
-/*
- * IP address helper.
- *
- * initialize a sockaddr_in from a
- * [<uid>'.'<gid>'@']<host>':'<path>" string and let
- * pPath point to the <path> 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)
-{
-struct hostent *h;
-char host[64];
-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 = geteuid();
- *pgid = getegid();
- chpt = *pPath;
- }
- if ( pHost )
- *pHost = chpt;
-
- /* split the device name which is in the form
- *
- * <host> ':' <path>
- *
- * 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;
-
- /* BEGIN OF NON-THREAD SAFE REGION */
-
- h = gethostbyname(host);
-
- if ( !h ) {
- errno = EINVAL;
- return -1;
- }
-
- memcpy(&psa->sin_addr, h->h_addr, sizeof (struct in_addr));
-
- /* END OF NON-THREAD SAFE REGION */
-
- 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
- *****************************************/
-
-static bool nfs_is_directory(
- rtems_filesystem_eval_path_context_t *ctx,
- void *arg
-)
-{
- bool is_dir = false;
- rtems_filesystem_location_info_t *currentloc =
- rtems_filesystem_eval_path_get_currentloc(ctx);
- NfsNode node = currentloc->node_access;
- int force_update = 0;
-
- if (updateAttr(node, force_update) == 0) {
- is_dir = SERP_ATTR(node).type == NFDIR;
- }
-
- return is_dir;
-}
-
-static int nfs_search_in_directory(
- Nfs nfs,
- const NfsNode dir,
- char *part,
- NfsNode entry
-)
-{
- int rv;
-
- entry->nfs = nfs;
-
- /* lookup one element */
- SERP_ATTR(entry) = SERP_ATTR(dir);
- SERP_FILE(entry) = SERP_FILE(dir);
- SERP_ARGS(entry).diroparg.name = part;
-
- /* remember args / directory fh */
- memcpy(&entry->args, &SERP_FILE(dir), sizeof(dir->args));
-
-#if DEBUG & DEBUG_EVALPATH
- fprintf(stderr,"Looking up '%s'\n",part);
-#endif
-
- rv = nfscall(
- nfs->server,
- NFSPROC_LOOKUP,
- (xdrproc_t) xdr_diropargs, &SERP_FILE(entry),
- (xdrproc_t) xdr_serporid, &entry->serporid
- );
-
- if (rv == 0 && entry->serporid.status == NFS_OK) {
- int force_update = 1;
-
- rv = updateAttr(entry, force_update);
- } else {
- rv = -1;
- }
-
- return rv;
-}
-
-static void nfs_eval_follow_link(
- rtems_filesystem_eval_path_context_t *ctx,
- NfsNode link
-)
-{
- const size_t len = NFS_MAXPATHLEN + 1;
- char *buf = malloc(len);
-
- if (buf != NULL) {
- ssize_t rv = nfs_readlink_with_node(link, buf, len);
-
- if (rv >= 0) {
- rtems_filesystem_eval_path_recursive(ctx, buf, (size_t) rv);
- } else {
- rtems_filesystem_eval_path_error(ctx, 0);
- }
-
- free(buf);
- } else {
- rtems_filesystem_eval_path_error(ctx, ENOMEM);
- }
-}
-
-static void nfs_eval_set_handlers(
- rtems_filesystem_eval_path_context_t *ctx,
- ftype type
-)
-{
- rtems_filesystem_location_info_t *currentloc =
- rtems_filesystem_eval_path_get_currentloc(ctx);
-
- switch (type) {
- case NFDIR:
- currentloc->handlers = &nfs_dir_file_handlers;
- break;
- case NFREG:
- currentloc->handlers = &nfs_file_file_handlers;
- break;
- case NFLNK:
- currentloc->handlers = &nfs_link_file_handlers;
- break;
- default:
- currentloc->handlers = &rtems_filesystem_handlers_default;
- break;
- }
-}
-
-static int nfs_move_node(NfsNode dst, const NfsNode src, const char *part)
-{
- int rv = 0;
-
- if (dst->str != NULL) {
-#if DEBUG & DEBUG_COUNT_NODES
- rtems_interrupt_lock_context lock_context;
- NFS_GLOBAL_ACQUIRE(&lock_context);
- dst->nfs->stringsInUse--;
- NFS_GLOBAL_RELEASE(&lock_context);
-#endif
- free(dst->str);
- }
-
- *dst = *src;
-
- dst->str = dst->args.name = strdup(part);
- if (dst->str != NULL) {
-#if DEBUG & DEBUG_COUNT_NODES
- rtems_interrupt_lock_context lock_context;
- NFS_GLOBAL_ACQUIRE(&lock_context);
- dst->nfs->stringsInUse++;
- NFS_GLOBAL_RELEASE(&lock_context);
-#endif
- } else {
- rv = -1;
- }
-
- return rv;
-}
-
-static rtems_filesystem_eval_path_generic_status nfs_eval_part(
- rtems_filesystem_eval_path_context_t *ctx,
- char *part
-)
-{
- rtems_filesystem_eval_path_generic_status status =
- RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
- rtems_filesystem_location_info_t *currentloc =
- rtems_filesystem_eval_path_get_currentloc(ctx);
- Nfs nfs = currentloc->mt_entry->fs_info;
- NfsNode dir = currentloc->node_access;
- NfsNodeRec entry;
- int rv = nfs_search_in_directory(nfs, dir, part, &entry);
-
- if (rv == 0) {
- bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
- int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
- bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
- ftype type = SERP_ATTR(&entry).type;
-
- rtems_filesystem_eval_path_clear_token(ctx);
-
- if (type == NFLNK && (follow_sym_link || !terminal)) {
- nfs_eval_follow_link(ctx, &entry);
- } else {
- rv = nfs_move_node(dir, &entry, part);
- if (rv == 0) {
- nfs_eval_set_handlers(ctx, type);
- if (!terminal) {
- status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
- }
- } else {
- rtems_filesystem_eval_path_error(ctx, ENOMEM);
- }
- }
- } else {
- status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
- }
-
- return status;
-}
-
-static rtems_filesystem_eval_path_generic_status nfs_eval_token(
- rtems_filesystem_eval_path_context_t *ctx,
- void *arg,
- const char *token,
- size_t tokenlen
-)
-{
- rtems_filesystem_eval_path_generic_status status =
- RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
-
- if (rtems_filesystem_is_current_directory(token, tokenlen)) {
- rtems_filesystem_eval_path_clear_token(ctx);
- if (rtems_filesystem_eval_path_has_path(ctx)) {
- status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
- }
- } else {
- char *part = nfs_dupname(token, tokenlen);
-
- if (part != NULL) {
- status = nfs_eval_part(ctx, part);
- free(part);
- } else {
- rtems_filesystem_eval_path_error(ctx, ENOMEM);
- }
- }
-
- return status;
-}
-
-static const rtems_filesystem_eval_path_generic_config nfs_eval_config = {
- .is_directory = nfs_is_directory,
- .eval_token = nfs_eval_token
-};
-
-static void nfs_eval_path(rtems_filesystem_eval_path_context_t *ctx)
-{
- rtems_filesystem_eval_path_generic(ctx, NULL, &nfs_eval_config);
-}
-
-/* create a hard link */
-
-static int nfs_link(
- const rtems_filesystem_location_info_t *parentloc,
- const rtems_filesystem_location_info_t *targetloc,
- const char *name,
- size_t namelen
-)
-{
-int rv = 0;
-NfsNode pNode = parentloc->node_access;
-nfsstat status;
-NfsNode tNode = targetloc->node_access;
-char *dupname;
-
- dupname = nfs_dupname(name, namelen);
- if (dupname == NULL)
- return -1;
-
-#if DEBUG & DEBUG_SYSCALLS
- fprintf(stderr,"Creating link '%s'\n",dupname);
-#endif
-
- memcpy(&SERP_ARGS(tNode).linkarg.to.dir,
- &SERP_FILE(pNode),
- sizeof(SERP_FILE(pNode)));
-
- SERP_ARGS(tNode).linkarg.to.name = dupname;
-
- rv = nfscall(
- tNode->nfs->server,
- NFSPROC_LINK,
- (xdrproc_t)xdr_linkargs, &SERP_FILE(tNode),
- (xdrproc_t)xdr_nfsstat, &status
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(status);
-#if DEBUG & DEBUG_SYSCALLS
- if (rv != 0) {
- perror("nfs_link");
- }
-#endif
- }
-
- free(dupname);
-
- return rv;
-
-}
-
-static int nfs_do_unlink(
- const rtems_filesystem_location_info_t *parentloc,
- const rtems_filesystem_location_info_t *loc,
- int proc
-)
-{
-int rv = 0;
-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
-
- rv = nfscall(
- nfs->server,
- proc,
- (xdrproc_t)xdr_diropargs, &node->args,
- (xdrproc_t)xdr_nfsstat, &status
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(status);
-#if DEBUG & DEBUG_SYSCALLS
- if (rv != 0) {
- perror(name);
- }
-#endif
- }
-
- return rv;
-}
-
-static int nfs_chown(
- const 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);
-
-}
-
-static int nfs_clonenode(rtems_filesystem_location_info_t *loc)
-{
- NfsNode node = loc->node_access;
-
- LOCK(nfsGlob.lock);
- node = nfsNodeClone(node);
- UNLOCK(nfsGlob.lock);
-
- loc->node_access = node;
-
- return node != NULL ? 0 : -1;
-}
-
-/* Cleanup the FS private info attached to pathloc->node_access */
-static void nfs_freenode(
- const rtems_filesystem_location_info_t *pathloc /* IN */
-)
-{
-#if DEBUG & DEBUG_COUNT_NODES
-Nfs nfs = ((NfsNode)pathloc->node_access)->nfs;
-
- /* print counts at entry where they are > 0 so 'nfs' is safe from being destroyed
- * and there's no race condition
- */
- fprintf(stderr,
- "entering freenode, in use count is %i nodes, %i strings\n",
- nfs->nodesInUse,
- nfs->stringsInUse);
-#endif
-
- nfsNodeDestroy(pathloc->node_access);
-}
-
-/* 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.
- */
-
-int rtems_nfs_initialize(
- rtems_filesystem_mount_table_entry_t *mt_entry,
- const void *data
-)
-{
-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 (rpcUdpInit () < 0) {
- fprintf (stderr, "error: initialising RPC\n");
- return -1;
- }
-
- if (nfsInit(0, 0) != 0) {
- fprintf (stderr, "error: initialising NFS\n");
- return -1;
- };
-
-#if 0
- printf("Trying to mount %s on %s\n",path,mntpoint);
-#endif
-
- 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,
- (xdrproc_t)xdr_void, 0,
- (xdrproc_t)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,
- (xdrproc_t)xdr_dirpath,
- &path,
- (xdrproc_t)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;
- }
-
- nfs = nfsCreate(nfsServer);
- assert( nfs );
- 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
- */
- rootNode = nfsNodeCreate(nfs, &fhstat.fhstatus_u.fhs_fhandle);
- assert( rootNode );
-
- if ( updateAttr(rootNode, 1 /* force */) ) {
- e = errno;
- goto cleanup;
- }
-
- /* looks good so far */
-
- mt_entry->mt_fs_root->location.node_access = rootNode;
-
- rootNode = 0;
-
- mt_entry->ops = &nfs_fs_ops;
- mt_entry->mt_fs_root->location.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 void 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;
-int status;
-
-LOCK(nfsGlob.llock);
- nodesInUse = ((Nfs)mt_entry->fs_info)->nodesInUse;
-
- if (nodesInUse > 1 /* one ref to the root node used by us */) {
- UNLOCK(nfsGlob.llock);
- fprintf(stderr,
- "Refuse to unmount; there are still %i nodes in use (1 used by us)\n",
- nodesInUse);
- rtems_fatal_error_occurred(0xdeadbeef);
- return;
- }
-
- status = buildIpAddr(&uid, &gid, 0, &saddr, &path);
- assert( !status );
-
- stat = mntcall( &saddr,
- MOUNTPROC_UMNT,
- (xdrproc_t)xdr_dirpath, &path,
- (xdrproc_t)xdr_void, 0,
- uid,
- gid
- );
-
- if (stat) {
- UNLOCK(nfsGlob.llock);
- fprintf(stderr,"NFS UMOUNT -- %s\n", clnt_sperrno(stat));
- return;
- }
-
- nfsNodeDestroy(mt_entry->mt_fs_root->location.node_access);
- mt_entry->mt_fs_root->location.node_access = 0;
-
- nfsDestroy(mt_entry->fs_info);
- mt_entry->fs_info = 0;
-
- nfsGlob.num_mounted_fs--;
-UNLOCK(nfsGlob.llock);
-}
-
-static int nfs_mknod(
- const rtems_filesystem_location_info_t *parentloc,
- const char *name,
- size_t namelen,
- mode_t mode,
- dev_t dev
-)
-{
-
-int rv = 0;
-struct timeval now;
-diropres res;
-NfsNode node = parentloc->node_access;
-Nfs nfs = node->nfs;
-mode_t type = S_IFMT & mode;
-char *dupname;
-
- if (type != S_IFDIR && type != S_IFREG)
- rtems_set_errno_and_return_minus_one(ENOTSUP);
-
- dupname = nfs_dupname(name, namelen);
- if (dupname == NULL)
- return -1;
-
-#if DEBUG & DEBUG_SYSCALLS
- fprintf(stderr,"nfs_mknod: creating %s\n", dupname);
-#endif
-
- rtems_clock_get_tod_timeval(&now);
-
- SERP_ARGS(node).createarg.name = dupname;
- SERP_ARGS(node).createarg.attributes.mode = mode;
- SERP_ARGS(node).createarg.attributes.uid = nfs->uid;
- SERP_ARGS(node).createarg.attributes.gid = nfs->gid;
- SERP_ARGS(node).createarg.attributes.size = 0;
- SERP_ARGS(node).createarg.attributes.atime.seconds = now.tv_sec;
- SERP_ARGS(node).createarg.attributes.atime.useconds = now.tv_usec;
- SERP_ARGS(node).createarg.attributes.mtime.seconds = now.tv_sec;
- SERP_ARGS(node).createarg.attributes.mtime.useconds = now.tv_usec;
-
- rv = nfscall(
- nfs->server,
- (type == S_IFDIR) ? NFSPROC_MKDIR : NFSPROC_CREATE,
- (xdrproc_t)xdr_createargs, &SERP_FILE(node),
- (xdrproc_t)xdr_diropres, &res
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(res.status);
-#if DEBUG & DEBUG_SYSCALLS
- if (rv != 0) {
- perror("nfs_mknod");
- }
-#endif
- }
-
- free(dupname);
-
- return rv;
-}
-
-static int nfs_rmnod(
- const rtems_filesystem_location_info_t *parentloc,
- const rtems_filesystem_location_info_t *loc
-)
-{
- int rv = 0;
- NfsNode node = loc->node_access;
- int force_update = 0;
-
- if (updateAttr(node, force_update) == 0) {
- int proc = SERP_ATTR(node).type == NFDIR
- ? NFSPROC_RMDIR
- : NFSPROC_REMOVE;
-
- rv = nfs_do_unlink(parentloc, loc, proc);
- } else {
- rv = -1;
- }
-
- return rv;
-}
-
-static int nfs_utime(
- const 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(
- const rtems_filesystem_location_info_t *parentloc,
- const char *name,
- size_t namelen,
- const char *target
-)
-{
-int rv = 0;
-struct timeval now;
-nfsstat status;
-NfsNode node = parentloc->node_access;
-Nfs nfs = node->nfs;
-char *dupname;
-
- dupname = nfs_dupname(name, namelen);
- if (dupname == NULL)
- return -1;
-
-#if DEBUG & DEBUG_SYSCALLS
- fprintf(stderr,"nfs_symlink: creating %s -> %s\n", dupname, target);
-#endif
-
- rtems_clock_get_tod_timeval(&now);
-
- SERP_ARGS(node).symlinkarg.name = dupname;
- SERP_ARGS(node).symlinkarg.to = (nfspath) target;
-
- SERP_ARGS(node).symlinkarg.attributes.mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
- SERP_ARGS(node).symlinkarg.attributes.uid = nfs->uid;
- SERP_ARGS(node).symlinkarg.attributes.gid = nfs->gid;
- SERP_ARGS(node).symlinkarg.attributes.size = 0;
- SERP_ARGS(node).symlinkarg.attributes.atime.seconds = now.tv_sec;
- SERP_ARGS(node).symlinkarg.attributes.atime.useconds = now.tv_usec;
- SERP_ARGS(node).symlinkarg.attributes.mtime.seconds = now.tv_sec;
- SERP_ARGS(node).symlinkarg.attributes.mtime.useconds = now.tv_usec;
-
- rv = nfscall(
- nfs->server,
- NFSPROC_SYMLINK,
- (xdrproc_t)xdr_symlinkargs, &SERP_FILE(node),
- (xdrproc_t)xdr_nfsstat, &status
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(status);
-#if DEBUG & DEBUG_SYSCALLS
- perror("nfs_symlink");
-#endif
- }
-
- free(dupname);
-
- return rv;
-}
-
-static ssize_t nfs_readlink_with_node(
- NfsNode node,
- char *buf,
- size_t len
-)
-{
- ssize_t rv;
- Nfs nfs = node->nfs;
- readlinkres_strbuf rr;
-
- rr.strbuf.buf = buf;
- rr.strbuf.max = len - 1;
-
- rv = nfscall(
- nfs->server,
- NFSPROC_READLINK,
- (xdrproc_t)xdr_nfs_fh, &SERP_FILE(node),
- (xdrproc_t)xdr_readlinkres_strbuf, &rr
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(rr.status);
-
- if (rv == 0) {
- rv = (ssize_t) strlen(rr.strbuf.buf);
- } else {
-#if DEBUG & DEBUG_SYSCALLS
- perror("nfs_readlink_with_node");
-#endif
- }
- }
-
- return rv;
-}
-
-static ssize_t nfs_readlink(
- const rtems_filesystem_location_info_t *loc,
- char *buf,
- size_t len
-)
-{
- NfsNode node = loc->node_access;
-
- return nfs_readlink_with_node(node, buf, len);
-}
-
-static int nfs_rename(
- const rtems_filesystem_location_info_t *oldparentloc,
- const rtems_filesystem_location_info_t *oldloc,
- const rtems_filesystem_location_info_t *newparentloc,
- const char *name,
- size_t namelen
-)
-{
- int rv = 0;
- char *dupname = nfs_dupname(name, namelen);
-
- if (dupname != NULL) {
- NfsNode oldParentNode = oldparentloc->node_access;
- NfsNode oldNode = oldloc->node_access;
- NfsNode newParentNode = newparentloc->node_access;
- Nfs nfs = oldParentNode->nfs;
- const nfs_fh *toDirSrc = &SERP_FILE(newParentNode);
- nfs_fh *toDirDst = &SERP_ARGS(oldParentNode).renamearg.to.dir;
- nfsstat status;
-
- SERP_ARGS(oldParentNode).renamearg.name = oldNode->str;
- SERP_ARGS(oldParentNode).renamearg.to.name = dupname;
- memcpy(toDirDst, toDirSrc, sizeof(*toDirDst));
-
- rv = nfscall(
- nfs->server,
- NFSPROC_RENAME,
- (xdrproc_t) xdr_renameargs,
- &SERP_FILE(oldParentNode),
- (xdrproc_t) xdr_nfsstat,
- &status
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(status);
- }
-
- free(dupname);
- } else {
- rv = -1;
- }
-
- return rv;
-}
-
-static void nfs_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
-{
-}
-
-static void nfs_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
-{
-}
-
-static bool nfs_are_nodes_equal(
- const rtems_filesystem_location_info_t *a,
- const rtems_filesystem_location_info_t *b
-)
-{
- bool equal = false;
- NfsNode na = a->node_access;
-
- if (updateAttr(na, 0) == 0) {
- NfsNode nb = b->node_access;
-
- if (updateAttr(nb, 0) == 0) {
- equal = SERP_ATTR(na).fileid == SERP_ATTR(nb).fileid
- && SERP_ATTR(na).fsid == SERP_ATTR(nb).fsid;
- }
- }
-
- return equal;
-}
-
-static int nfs_fchmod(
- const rtems_filesystem_location_info_t *loc,
- mode_t mode
-)
-{
-sattr arg;
-
- arg.mode = mode;
- return nfs_sattr(loc->node_access, &arg, SATTR_MODE);
-
-}
-
-const struct _rtems_filesystem_operations_table nfs_fs_ops = {
- .lock_h = nfs_lock,
- .unlock_h = nfs_unlock,
- .eval_path_h = nfs_eval_path,
- .link_h = nfs_link,
- .are_nodes_equal_h = nfs_are_nodes_equal,
- .mknod_h = nfs_mknod,
- .rmnod_h = nfs_rmnod,
- .fchmod_h = nfs_fchmod,
- .chown_h = nfs_chown,
- .clonenod_h = nfs_clonenode,
- .freenod_h = nfs_freenode,
- .mount_h = rtems_filesystem_default_mount,
- .unmount_h = rtems_filesystem_default_unmount,
- .fsunmount_me_h = nfs_fsunmount_me,
- .utime_h = nfs_utime,
- .symlink_h = nfs_symlink,
- .readlink_h = nfs_readlink,
- .rename_h = nfs_rename,
- .statvfs_h = rtems_filesystem_default_statvfs
-};
-
-/*****************************************
- 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'.
- *****************************************/
-
-/* stateless NFS protocol makes this trivial */
-static int nfs_file_open(
- rtems_libio_t *iop,
- const char *pathname,
- int oflag,
- mode_t mode
-)
-{
- 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 pathinfo.node_access_2.
- */
-static int nfs_dir_open(
- rtems_libio_t *iop,
- const char *pathname,
- int oflag,
- mode_t mode
-)
-{
-NfsNode node = iop->pathinfo.node_access;
-DirInfo di;
-
- /* create a readdirargs object and copy the file handle;
- * attach to the pathinfo.node_access_2
- */
-
- di = (DirInfo) malloc(sizeof(*di));
- iop->pathinfo.node_access_2 = 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;
-}
-
-static int nfs_file_close(
- rtems_libio_t *iop
-)
-{
- return 0;
-}
-
-static int nfs_dir_close(
- rtems_libio_t *iop
-)
-{
- free(iop->pathinfo.node_access_2);
- iop->pathinfo.node_access_2 = 0;
- return 0;
-}
-
-static ssize_t nfs_file_read_chunk(
- NfsNode node,
- uint32_t offset,
- void *buffer,
- size_t count
-)
-{
-ssize_t rv;
-readres rr;
-Nfs nfs = node->nfs;
-
- SERP_ARGS(node).readarg.offset = offset;
- SERP_ARGS(node).readarg.count = count;
- SERP_ARGS(node).readarg.totalcount = UINT32_C(0xdeadbeef);
-
- rr.readres_u.reply.data.data_val = buffer;
-
- rv = nfscall(
- nfs->server,
- NFSPROC_READ,
- (xdrproc_t)xdr_readargs, &SERP_FILE(node),
- (xdrproc_t)xdr_readres, &rr
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(rr.status);
-
- if (rv == 0) {
- rv = rr.readres_u.reply.data.data_len;
-
-#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 rv;
-}
-
-static ssize_t nfs_file_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
- ssize_t rv = 0;
- NfsNode node = iop->pathinfo.node_access;
- uint32_t offset = iop->offset;
- char *in = buffer;
-
- if (iop->offset < 0) {
- errno = EINVAL;
- return -1;
- }
-
- if ((uintmax_t) iop->offset >= UINT32_MAX) {
- errno = EFBIG;
- return -1;
- }
-
- if (count > UINT32_MAX - offset) {
- count = UINT32_MAX - offset;
- }
-
- do {
- size_t chunk = count <= NFS_MAXDATA ? count : NFS_MAXDATA;
- ssize_t done = nfs_file_read_chunk(node, offset, in, chunk);
-
- if (done > 0) {
- offset += (uint32_t) done;
- in += done;
- count -= (size_t) done;
- rv += done;
- } else {
- count = 0;
- if (done < 0) {
- rv = -1;
- }
- }
- } while (count > 0);
-
- if (rv > 0) {
- iop->offset = offset;
- }
-
- return rv;
-}
-
-/* this is called by readdir() / getdents() */
-static ssize_t nfs_dir_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
-ssize_t rv;
-DirInfo di = iop->pathinfo.node_access_2;
-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
-
- rv = nfscall(
- server,
- NFSPROC_READDIR,
- (xdrproc_t)xdr_readdirargs, &di->readdirargs,
- (xdrproc_t)xdr_dir_info, di
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(di->status);
-
- if (rv == 0) {
- rv = (char*)di->ptr - (char*)buffer;
- }
- }
-
- return rv;
-}
-
-static ssize_t nfs_file_write(
- rtems_libio_t *iop,
- const void *buffer,
- size_t count
-)
-{
-ssize_t rv;
-NfsNode node = iop->pathinfo.node_access;
-Nfs nfs = node->nfs;
-
- if (count > NFS_MAXDATA)
- count = NFS_MAXDATA;
-
-
- SERP_ARGS(node).writearg.beginoffset = UINT32_C(0xdeadbeef);
- if (rtems_libio_iop_is_append(iop)) {
- if ( updateAttr(node, 0) ) {
- return -1;
- }
- if (SERP_ATTR(node).size >= UINT32_MAX) {
- errno = EFBIG;
- return -1;
- }
- SERP_ARGS(node).writearg.offset = SERP_ATTR(node).size;
- } else {
- if (iop->offset < 0) {
- errno = EINVAL;
- return -1;
- }
- if ((uintmax_t) iop->offset >= UINT32_MAX) {
- errno = EFBIG;
- return -1;
- }
- SERP_ARGS(node).writearg.offset = iop->offset;
- }
-
- if (count > UINT32_MAX - SERP_ARGS(node).writearg.offset) {
- count = UINT32_MAX - SERP_ARGS(node).writearg.offset;
- }
-
- SERP_ARGS(node).writearg.totalcount = UINT32_C(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
- */
-
- rv = nfscall(
- nfs->server,
- NFSPROC_WRITE,
- (xdrproc_t)xdr_writeargs, &SERP_FILE(node),
- (xdrproc_t)xdr_attrstat, &node->serporid
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(node->serporid.status);
-
- if (rv == 0) {
- node->age = nowSeconds();
-
- iop->offset += count;
- rv = count;
- } else {
- /* try at least to recover the current attributes */
- updateAttr(node, 1 /* force */);
- }
- }
-
- return rv;
-}
-
-static off_t nfs_dir_lseek(
- rtems_libio_t *iop,
- off_t length,
- int whence
-)
-{
- off_t rv = rtems_filesystem_default_lseek_directory(iop, length, whence);
-
- if (rv == 0) {
- DirInfo di = iop->pathinfo.node_access_2;
- nfscookie *cookie = &di->readdirargs.cookie;
-
- di->eofreached = FALSE;
-
- /* rewind cookie */
- memset(cookie, 0, sizeof(*cookie));
- }
-
- return rv;
-}
-
-#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(
- const 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;
- /* Set to "preferred size" of this NFS client implementation */
- buf->st_blksize = nfsStBlksize ? nfsStBlksize : 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)
-{
-int rv;
-struct timeval now;
-nfstime nfsnow, t;
-u_int mode;
-
- if (updateAttr(node, 0 /* only if old */))
- return -1;
-
- rtems_clock_get_tod_timeval(&now);
-
- /* TODO: add rtems EPOCH - UNIX EPOCH seconds */
- nfsnow.seconds = now.tv_sec;
- nfsnow.useconds = now.tv_usec;
-
- /* merge permission bits into existing type bits */
- mode = SERP_ATTR(node).mode;
- if (mask & SATTR_MODE) {
- mode &= S_IFMT;
- mode |= arg->mode & ~S_IFMT;
- } else {
- mode = -1;
- }
- SERP_ARGS(node).sattrarg.attributes.mode = mode;
-
- SERP_ARGS(node).sattrarg.attributes.uid =
- (mask & SATTR_UID) ? arg->uid : -1;
-
- SERP_ARGS(node).sattrarg.attributes.gid =
- (mask & SATTR_GID) ? arg->gid : -1;
-
- SERP_ARGS(node).sattrarg.attributes.size =
- (mask & SATTR_SIZE) ? arg->size : -1;
-
- if (mask & SATTR_ATIME)
- t = arg->atime;
- else if (mask & SATTR_TOUCHA)
- t = nfsnow;
- else
- t.seconds = t.useconds = -1;
- SERP_ARGS(node).sattrarg.attributes.atime = t;
-
- if (mask & SATTR_ATIME)
- t = arg->mtime;
- else if (mask & SATTR_TOUCHA)
- t = nfsnow;
- else
- t.seconds = t.useconds = -1;
- SERP_ARGS(node).sattrarg.attributes.mtime = t;
-
- node->serporid.status = NFS_OK;
-
- rv = nfscall(
- node->nfs->server,
- NFSPROC_SETATTR,
- (xdrproc_t)xdr_sattrargs, &SERP_FILE(node),
- (xdrproc_t)xdr_attrstat, &node->serporid
- );
-
- if (rv == 0) {
- rv = nfsEvaluateStatus(node->serporid.status);
-
- if (rv == 0) {
- node->age = nowSeconds();
- } else {
-#if DEBUG & DEBUG_SYSCALLS
- fprintf(stderr,"nfs_sattr: %s\n",strerror(errno));
-#endif
- /* try at least to recover the current attributes */
- updateAttr(node, 1 /* force */);
- }
- } else {
-#if DEBUG & DEBUG_SYSCALLS
- fprintf(stderr,
- "nfs_sattr (mask 0x%08x): %s",
- mask,
- strerror(errno));
-#endif
- }
-
- return rv;
-}
-
-/* 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;
-
- if (length < 0) {
- errno = EINVAL;
- return -1;
- }
-
- if ((uintmax_t) length > UINT32_MAX) {
- errno = EFBIG;
- return -1;
- }
-
- arg.size = length;
- /* must not modify any other attribute; if we are not the owner
- * of the file or directory but only have write access changing
- * any attribute besides 'size' will fail...
- */
- return nfs_sattr(iop->pathinfo.node_access,
- &arg,
- SATTR_SIZE);
-}
-
-/* the file handlers table */
-static const
-struct _rtems_filesystem_file_handlers_r nfs_file_file_handlers = {
- .open_h = nfs_file_open,
- .close_h = nfs_file_close,
- .read_h = nfs_file_read,
- .write_h = nfs_file_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek_file,
- .fstat_h = nfs_fstat,
- .ftruncate_h = nfs_file_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-/* the directory handlers table */
-static const
-struct _rtems_filesystem_file_handlers_r nfs_dir_file_handlers = {
- .open_h = nfs_dir_open,
- .close_h = nfs_dir_close,
- .read_h = nfs_dir_read,
- .write_h = rtems_filesystem_default_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = nfs_dir_lseek,
- .fstat_h = nfs_fstat,
- .ftruncate_h = rtems_filesystem_default_ftruncate_directory,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-/* the link handlers table */
-static const
-struct _rtems_filesystem_file_handlers_r nfs_link_file_handlers = {
- .open_h = rtems_filesystem_default_open,
- .close_h = rtems_filesystem_default_close,
- .read_h = rtems_filesystem_default_read,
- .write_h = rtems_filesystem_default_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek,
- .fstat_h = nfs_fstat,
- .ftruncate_h = rtems_filesystem_default_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-/* 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->location))
- fprintf(f,"<UNABLE TO LOOKUP MOUNTPOINT>\n");
- else
- fprintf(f,"%s\n",mntpt);
- }
-
- UNLOCK(nfsGlob.llock);
-
- free(mntpt);
- return 0;
-}
-
-#if 0
-CCJ_REMOVE_MOUNT
-/* 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)
-{
-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((unsigned char)*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 ':<path>' */
- strcat(dev,":");
- strcat(dev,path);
- }
-
- printf("Trying to mount %s on %s\n",dev,mntpoint);
-
- if (mount(dev,
- mntpoint,
- "nfs",
- RTEMS_FILESYSTEM_READ_WRITE,
- NULL)) {
- perror("nfsMount - mount");
- goto cleanup;
- }
-
- rval = 0;
-
-cleanup:
- free(dev);
- return rval;
-}
-#endif
-
-/* 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_binary_semaphore 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->location;
-
- rtems_filesystem_current->location = *(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->location = old;
- }
- rtems_binary_semaphore_post(&rpa->sync);
- rtems_task_exit();
-}
-
-
-/* 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;
-
- rtems_binary_semaphore_init(&arg.sync, "NFSress");
-
- 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_binary_semaphore_wait(&arg.sync);
-
- status = arg.status;
-
-cleanup:
- rtems_binary_semaphore_destroy(&arg.sync);
-
- return status;
-}
-
-int
-nfsSetTimeout(uint32_t timeout_ms)
-{
-rtems_interrupt_lock_context lock_context;
-uint32_t s,us;
-
- if ( timeout_ms > 100000 ) {
- /* out of range */
- return -1;
- }
-
- s = timeout_ms/1000;
- us = (timeout_ms % 1000) * 1000;
-
- NFS_GLOBAL_ACQUIRE(&lock_context);
- _nfscalltimeout.tv_sec = s;
- _nfscalltimeout.tv_usec = us;
- NFS_GLOBAL_RELEASE(&lock_context);
-
- return 0;
-}
-
-uint32_t
-nfsGetTimeout( void )
-{
-rtems_interrupt_lock_context lock_context;
-uint32_t s,us;
- NFS_GLOBAL_ACQUIRE(&lock_context);
- s = _nfscalltimeout.tv_sec;
- us = _nfscalltimeout.tv_usec;
- NFS_GLOBAL_RELEASE(&lock_context);
- return s*1000 + us/1000;
-}
diff --git a/cpukit/libfs/src/nfsclient/src/nfsclient-private.h b/cpukit/libfs/src/nfsclient/src/nfsclient-private.h
deleted file mode 100644
index e1d81a40f6..0000000000
--- a/cpukit/libfs/src/nfsclient/src/nfsclient-private.h
+++ /dev/null
@@ -1,14 +0,0 @@
-struct mbuf;
-struct sockaddr;
-
-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));
-
-ssize_t recv_mbuf_from(int s, struct mbuf **ppm, long len,
- struct sockaddr *fromaddr, int *fromlen);
-
-struct __rpc_xdr;
-enum xdr_op;
-
-void xdrmbuf_create(struct __rpc_xdr *, struct mbuf *, enum xdr_op);
diff --git a/cpukit/libfs/src/nfsclient/src/rpcio.c b/cpukit/libfs/src/nfsclient/src/rpcio.c
deleted file mode 100644
index ce5abe3149..0000000000
--- a/cpukit/libfs/src/nfsclient/src/rpcio.c
+++ /dev/null
@@ -1,1774 +0,0 @@
-/**
- * @file
- *
- * @ingroup RTEMSFileSystemNFS
- *
- * @brief RPC Multiplexor for a Multitasking Environment
- *
- * 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).
- */
-
-/*
- * Author: Till Straumann <strauman@slac.stanford.edu>, 2002
- *
- * Authorship
- * ----------
- * This software (NFS-2 client implementation for RTEMS) was created by
- * Till Straumann <strauman@slac.stanford.edu>, 2002-2007,
- * Stanford Linear Accelerator Center, Stanford University.
- *
- * Acknowledgement of sponsorship
- * ------------------------------
- * The NFS-2 client implementation for RTEMS 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.
- *
- * Stanford disclaimer of copyright
- * --------------------------------
- * Stanford University, owner of the copyright, hereby disclaims its
- * copyright and all other rights in this software. Hence, anyone may
- * freely use it for any purpose without restriction.
- *
- * Maintenance of notices
- * ----------------------
- * In the interest of clarity regarding the origin and status of this
- * SLAC software, this and all the preceding Stanford University notices
- * are to remain affixed to any copy or derivative of this software made
- * or distributed by the recipient and are to be affixed to any copy of
- * software made or distributed by the recipient that contains a copy or
- * derivative of this software.
- *
- * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <inttypes.h>
-
-#include <rtems.h>
-#include <rtems/error.h>
-#include <rtems/rtems_bsdnet.h>
-#include <rtems/thread.h>
-#include <stdlib.h>
-#include <time.h>
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/cpuset.h>
-
-#include "rpcio.h"
-#include "nfsclient-private.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.
- */
-
-#undef REJECT_SERVERIP_MISMATCH
- /* If defined, RPC replies must come from the server
- * that was queried. Eric Norum has reported problems
- * with clustered NFS servers. So we disable this
- * reducing paranoia...
- */
-
-/* daemon task parameters */
-#define RPCIOD_STACK 10000
-#define RPCIOD_PRIO 100 /* *fallback* priority */
-
-/* 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) rtems_recursive_mutex_lock(&(mutex))
-
-#define MU_UNLOCK(mutex) rtems_recursive_mutex_unlock(&(mutex))
-
-#define MU_CREAT(pmutex) rtems_recursive_mutex_init((pmutex), "RPCl")
-
-#define MU_DESTROY(mutex) rtems_recursive_mutex_destroy(&(mutex))
-
-#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 */
- union {
- struct sockaddr_in sin;
- struct sockaddr sa;
- } addr;
- AUTH *auth;
- rtems_recursive_mutex 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_ {
- uint32_t 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 *)))
-#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};
-static u_long xidUpper [XACT_HASHS]={0};
-static unsigned xidHashSeed = 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
- */
-#ifndef NDEBUG
-static rtems_recursive_mutex llock; /* MUTEX protecting the server list */
-static rtems_recursive_mutex hlock; /* MUTEX protecting the hash table and the list of servers */
-#endif
-static rtems_binary_semaphore fini = RTEMS_BINARY_SEMAPHORE_INITIALIZER("RPCf"); /* a synchronization semaphore we use during
- * module cleanup / driver unloading
- */
-static rtems_interval ticksPerSec; /* cached system clock rate (WHO IS ASSUMED NOT
- * TO CHANGE)
- */
-
-rtems_task_priority rpciodPriority = 0;
-#ifdef RTEMS_SMP
-const cpu_set_t *rpciodCpuset = 0;
-size_t rpciodCpusetSize = 0;
-#endif
-
-#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)) != 0);
- 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)) != 0);
- 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,
- rpcprog_t prog,
- rpcvers_t 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;
- }
-
- len = getgroups(NGROUPS, gids);
- if (len < 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; i<len; i++)
- thegids[i] = (int)gids[i];
-
- theuid = (int) ((RPCIOD_DEFAULT_ID == uid) ? geteuid() : uid);
- thegid = (int) ((RPCIOD_DEFAULT_ID == gid) ? getegid() : gid);
-
- if ( !(auth = authunix_create(hname, theuid, thegid, len, thegids)) ) {
- fprintf(stderr,
- "RPCIO - error: unable to create RPC AUTH\n");
- return RPC_FAILED;
- }
-
- /* if they specified no port try to ask the portmapper */
- if (!paddr->sin_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.sin = *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",
- (unsigned)(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 */
- MU_LOCK(hlock);
- rval->obuf.xid = (xidHashSeed++ ^ ((uintptr_t)rval>>10)) & XACT_HASH_MSK;
- 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 = xidUpper[i] | 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;
- /* remember XID we used last time so we can avoid
- * reusing the same one (incremented by rpcUdpSend routine)
- */
- xidUpper[i] = xact->obuf.xid;
- 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;
-
- /* round lifetime to closest # of ticks */
- xact->lifetime = (ms * ticksPerSec + 500) / 1000;
- if ( 0 == xact->lifetime )
- xact->lifetime = 1;
-
-#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,(long*)&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_status_code status;
-rtems_event_set gotEvents;
-
- refresh = 0;
-
- do {
-
- /* block for the reply */
- status = rtems_event_receive(
- RTEMS_RPC_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT,
- &gotEvents);
- ASSERT( status == RTEMS_SUCCESSFUL );
-
- 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, void *arg)
-{
- rtems_id *rpciod = (rtems_id*) arg;
- rtems_event_send(*rpciod, RPCIOD_RX_EVENT);
-}
-
-void
-rpcSetXIDs(uint32_t xid)
-{
- uint32_t i;
-
- xid &= ~XACT_HASH_MSK;
-
- for (i = 0; i < XACT_HASHS; ++i) {
- xidUpper[i] = xid | i;
- }
-}
-
-int
-rpcUdpInit(void)
-{
-int s;
-rtems_status_code status;
-int noblock = 1;
-struct sockwakeup wkup;
-
- if (ourSock < 0) {
- fprintf(stderr,"RTEMS-RPCIOD, " \
- "Till Straumann, Stanford/SLAC/SSRL 2002, " \
- "See LICENSE file for licensing info.\n");
-
- ourSock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (ourSock>=0) {
- bindresvport(ourSock,(struct sockaddr_in*)0);
- s = ioctl(ourSock, FIONBIO, (char*)&noblock);
- assert( s == 0 );
- /* assume nobody tampers with the clock !! */
- ticksPerSec = rtems_clock_get_ticks_per_second();
- MU_CREAT( &hlock );
- MU_CREAT( &llock );
-
- if ( !rpciodPriority ) {
- /* use configured networking priority */
- if ( ! (rpciodPriority = rtems_bsdnet_config.network_task_priority) )
- rpciodPriority = RPCIOD_PRIO; /* fallback value */
- }
-
- status = rtems_task_create(
- rtems_build_name('R','P','C','d'),
- rpciodPriority,
- RPCIOD_STACK,
- RTEMS_DEFAULT_MODES,
- /* fprintf saves/restores FP registers on PPC :-( */
- RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT,
- &rpciod);
- assert( status == RTEMS_SUCCESSFUL );
-
-#ifdef RTEMS_SMP
- if ( rpciodCpuset == 0 ) {
- rpciodCpuset = rtems_bsdnet_config.network_task_cpuset;
- rpciodCpusetSize = rtems_bsdnet_config.network_task_cpuset_size;
- }
- if ( rpciodCpuset != 0 )
- rtems_task_set_affinity( rpciod, rpciodCpusetSize, rpciodCpuset );
-#endif
-
- wkup.sw_pfn = rxWakeupCB;
- wkup.sw_arg = &rpciod;
- assert( 0==setsockopt(ourSock, SOL_SOCKET, SO_RCVWAKEUP, &wkup, sizeof(wkup)) );
- status = rtems_message_queue_create(
- rtems_build_name('R','P','C','q'),
- RPCIOD_QDEPTH,
- sizeof(RpcUdpXact),
- RTEMS_DEFAULT_ATTRIBUTES,
- &msgQ);
- assert( status == RTEMS_SUCCESSFUL );
- status = rtems_task_start( rpciod, rpcio_daemon, 0 );
- assert( status == RTEMS_SUCCESSFUL );
-
- } else {
- return -1;
- }
- }
- return 0;
-}
-
-int
-rpcUdpCleanup(void)
-{
- rtems_event_send(rpciod, RPCIOD_KILL_EVENT);
- /* synchronize with daemon */
- rtems_binary_semaphore_wait_timed_ticks(&fini, 5*ticksPerSec);
- /* if the message queue is still there, something went wrong */
- if (!msgQ) {
- rtems_task_delete(rpciod);
- }
- 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,
- rpcprog_t prog,
- rpcvers_t 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;
-}
-
-static 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;
-size_t size;
-rtems_id q = 0;
-ListNodeRec listHead = {0, 0};
-unsigned long epoch = RPCIOD_EPOCH_SECS * ticksPerSec;
-unsigned long max_period = RPCIOD_RETX_CAP_S * ticksPerSec;
-rtems_status_code status;
-
-
- then = rtems_clock_get_ticks_since_boot();
-
- 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_binary_semaphore_post(&fini);
- } else {
- break;
- }
- }
-
- unow = rtems_clock_get_ticks_since_boot();
-
- /* 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++;
-
- /* Change the ID - there might still be
- * a reply on the way. When it arrives we
- * must not find it's ID in the hash table
- *
- * Thanks to Steven Johnson for hunting this
- * one down.
- */
- xact->obuf.xid += XACT_HASHS;
-
-#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: requestor id was 0x%08" PRIx32,
- 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,
- &srv->addr.sa,
- sizeof(srv->addr.sin)
-#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");
- status = rtems_event_send(xact->requestor, RTEMS_RPC_EVENT);
- assert( status == RTEMS_SUCCESSFUL );
-
- } 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;
- {
- long capped_period = srv->retry_period;
- if ( xact->lifetime < capped_period )
- capped_period = xact->lifetime;
- xact->age = now + capped_period;
- xact->tolive -= capped_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_binary_semaphore_post(&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(
- rpcprog_t prog, rpcvers_t version,
- int xactsize, int poolsize)
-{
-RpcUdpXactPool rval = MY_MALLOC(sizeof(*rval));
-rtems_status_code status;
-
- ASSERT( rval );
- status = rtems_message_queue_create(
- rtems_build_name('R','P','C','p'),
- poolsize,
- sizeof(RpcUdpXact),
- RTEMS_DEFAULT_ATTRIBUTES,
- &rval->box);
- assert( status == RTEMS_SUCCESSFUL );
-
- 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;
-size_t 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;
-
- pool = xact->pool;
- ASSERT( 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 <sys/mbuf.h>
-
-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;
-uint32_t xid;
-union {
- struct sockaddr_in sin;
- struct sockaddr sa;
-} fromAddr;
-int fromLen = sizeof(fromAddr.sin);
-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,
- &fromAddr.sa,
- &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,
- &fromAddr.sa,
- &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 ||
-#ifdef REJECT_SERVERIP_MISMATCH
- xact->server->addr.sin.sin_addr.s_addr != fromAddr.sin.sin_addr.s_addr ||
-#endif
- xact->server->addr.sin.sin_port != fromAddr.sin.sin_port ) {
-
- if (xact) {
- if (
-#ifdef REJECT_SERVERIP_MISMATCH
- xact->server->addr.sin.sin_addr.s_addr == fromAddr.sin.sin_addr.s_addr &&
-#endif
- xact->server->addr.sin.sin_port == fromAddr.sin.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%08" PRIx32 " -- got 0x%08" PRIx32 "\n",
- xact->obuf.xid, xid);
- fprintf(stderr,"xact: addr 0x%08" PRIx32 " -- got 0x%08" PRIx32 "\n",
- xact->server->addr.sin.sin_addr.s_addr,
- fromAddr.sin.sin_addr.s_addr);
- fprintf(stderr,"xact: port 0x%08x -- got 0x%08x\n",
- xact->server->addr.sin.sin_port,
- fromAddr.sin.sin_port);
- }
- } else {
- fprintf(stderr,
- "RPCIO WARNING sockRcv(): got xid 0x%08" PRIx32 " 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 <rtems/rtems_bsdnet_internal.h>
-/* 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/cpukit/libfs/src/nfsclient/src/rpcio.h b/cpukit/libfs/src/nfsclient/src/rpcio.h
deleted file mode 100644
index bc88e768c0..0000000000
--- a/cpukit/libfs/src/nfsclient/src/rpcio.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * @file
- *
- * @brief A Multithreaded RPC/UDP Multiplexor
- *
- * @ingroup rtems-nfsclient
- */
-
-/*
- * Author: Till Straumann, <strauman@slac.stanford.edu>, 2002
- *
- * Authorship
- * ----------
- * This software (NFS-2 client implementation for RTEMS) was created by
- * Till Straumann <strauman@slac.stanford.edu>, 2002-2007,
- * Stanford Linear Accelerator Center, Stanford University.
- *
- * Acknowledgement of sponsorship
- * ------------------------------
- * The NFS-2 client implementation for RTEMS 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.
- *
- * Stanford disclaimer of copyright
- * --------------------------------
- * Stanford University, owner of the copyright, hereby disclaims its
- * copyright and all other rights in this software. Hence, anyone may
- * freely use it for any purpose without restriction.
- *
- * Maintenance of notices
- * ----------------------
- * In the interest of clarity regarding the origin and status of this
- * SLAC software, this and all the preceding Stanford University notices
- * are to remain affixed to any copy or derivative of this software made
- * or distributed by the recipient and are to be affixed to any copy of
- * software made or distributed by the recipient that contains a copy or
- * derivative of this software.
- *
- * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
- */
-
-#ifndef RPCIO_H
-#define RPCIO_H
-
-/**
- * @defgroup rtems-nfsclient RPC/UDP Multiplexor
- *
- * @ingroup nfsclient
- * @{
- */
-
-#include <rpc/rpc.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <stdarg.h>
-
-#include "librtemsNfs.h"
-
-typedef struct RpcUdpServerRec_ *RpcUdpServer;
-typedef struct RpcUdpXactRec_ *RpcUdpXact;
-
-typedef RpcUdpXact RpcUdpClnt;
-
-#define RPCIOD_DEFAULT_ID 0xdef10000
-
-enum clnt_stat
-rpcUdpServerCreate(
- struct sockaddr_in *paddr,
- rpcprog_t prog,
- rpcvers_t 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);
-
-/**
- * @brief Dump statistics to a file (stdout if NULL);
- * @retval 0 for convenience
- */
-int
-rpcUdpStats(FILE *f);
-
-enum clnt_stat
-rpcUdpClntCreate(
- struct sockaddr_in *psaddr,
- rpcprog_t prog,
- rpcvers_t 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);
-
-/**
- * @brief 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 */
- );
-
-/**
- * @brief 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 */
-);
-
-
-
-/*
- * @brief 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(
- rpcprog_t prog, rpcvers_t 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/cpukit/libfs/src/nfsclient/src/sock_mbuf.c b/cpukit/libfs/src/nfsclient/src/sock_mbuf.c
deleted file mode 100644
index fa519f70fa..0000000000
--- a/cpukit/libfs/src/nfsclient/src/sock_mbuf.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * @file
- *
- * @ingroup RTEMSFileSystemNFS
- *
- * @brief Sock Mbuf
- */
-
-/*
- * 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, <strauman@slac.stanford.edu>
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define _KERNEL
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include <rtems.h>
-#include <rtems/libio.h>
-#include <rtems/error.h>
-
-#include <rtems/rtems_bsdnet.h>
-
-#include <sys/errno.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/protosw.h>
-#include <sys/proc.h>
-#include <sys/fcntl.h>
-#include <sys/filio.h>
-
-#include <net/if.h>
-#include <net/route.h>
-
-#include "nfsclient-private.h"
-
-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/cpukit/libfs/src/nfsclient/src/xdr_mbuf.c b/cpukit/libfs/src/nfsclient/src/xdr_mbuf.c
deleted file mode 100644
index 20f2f9f6e8..0000000000
--- a/cpukit/libfs/src/nfsclient/src/xdr_mbuf.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/**
- * @file
- *
- * @ingroup RTEMSFileSystemNFS
- *
- * @brief XDR Implementation Using mbuf Buffers
- *
- * xdr_mbuf is derived from xdr_mem
- */
-
-/*
- * Author (mbuf specifica): Till Straumann <strauman@slac.stanford.edu>, 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/param.h>
-#include <string.h>
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-#include <netinet/in.h>
-
-#include <stdlib.h>
-
-#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 <sys/mbuf.h>
-
-#include <assert.h>
-
-#if DEBUG & DEBUG_VERB || defined(TODO)
-#include <stdio.h>
-#endif
-
-#include "nfsclient-private.h"
-
-static bool_t xdrmbuf_getlong_aligned(XDR *xdrs, long *lp);
-static bool_t xdrmbuf_putlong_aligned(XDR *xdrs, const long *lp);
-static bool_t xdrmbuf_getlong_unaligned(XDR *xdrs, long *lp);
-static bool_t xdrmbuf_putlong_unaligned(XDR *xdrs, const long *lp);
-static bool_t xdrmbuf_getbytes(XDR *xdrs, caddr_t addr, u_int len);
-static bool_t xdrmbuf_putbytes(XDR *xdrs, const char *addr, u_int len);
-static u_int xdrmbuf_getpos(XDR *xdrs); /* XXX w/64-bit pointers, u_int not enough! */
-static bool_t xdrmbuf_setpos(XDR *xdrs, u_int pos);
-static int32_t *xdrmbuf_inline_aligned(XDR *xdrs, u_int len);
-static int32_t *xdrmbuf_inline_unaligned(XDR *xdrs, u_int len);
-static void xdrmbuf_destroy(XDR *);
-
-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 = ((uintptr_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;
- mbp = (MBPrivate)my_malloc(sizeof(*mbp));
- assert( 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; ii<mbf->m_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(
- XDR *xdrs,
- const 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(
- 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(
- XDR *xdrs,
- const 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(
- XDR *xdrs,
- caddr_t addr,
- 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(
- XDR *xdrs,
- const char *addr,
- 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(
- XDR *xdrs)
-{
-#if 1
-MBPrivate mbp = (MBPrivate)xdrs->x_base;
-struct mbuf *m = mbp->mcurrent;
-u_int rval = mbp->pos;
-
- if (m) {
- rval += xdrs->x_private - mtod(m, void*);
- }
-#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(
- 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(
- XDR *xdrs,
- u_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(
- XDR *xdrs,
- u_int len )
-{
- return (0);
-}