diff options
author | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-02-24 19:08:51 -0700 |
---|---|---|
committer | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-04-07 16:15:38 -0600 |
commit | 6692e03e9d1b8fae6526b828460c96b3db18d1d5 (patch) | |
tree | 4927275a0dec414792a152b5301e73e09716948e /cpukit/libfs/src/nfsclient/src/nfs.c | |
parent | cpukit: remove pppd (diff) | |
download | rtems-6692e03e9d1b8fae6526b828460c96b3db18d1d5.tar.bz2 |
cpukit/libfs: Remove nfsclient
Update #3850
Diffstat (limited to '')
-rw-r--r-- | cpukit/libfs/src/nfsclient/src/nfs.c | 3203 |
1 files changed, 0 insertions, 3203 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; -} |