summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2021-08-31 18:46:37 +1000
committerChris Johns <chrisj@rtems.org>2021-09-02 08:45:12 +1000
commit7e282d25068ec09163e00cbe5819a1b5be3571be (patch)
treeda34bc8eb2261a6037f212d40ad6682777e4c76c
parentkern/sys: Add NFSv4 client (diff)
downloadrtems-libbsd-7e282d25068ec09163e00cbe5819a1b5be3571be.tar.bz2
rtemsbsd/nfs: Add support to mount NFSv2
- NFSv2 requires userland RPC calls to determine the version of NFS and the FH. This is passed to the kernel. - Port more libc/rpc. Update #4475
-rw-r--r--buildset/default.ini2
-rw-r--r--config.inc7
-rw-r--r--freebsd/lib/libc/rpc/auth_unix.c7
-rw-r--r--freebsd/lib/libc/rpc/clnt_dg.c17
-rw-r--r--freebsd/lib/libc/rpc/clnt_generic.c5
-rw-r--r--freebsd/lib/libc/rpc/clnt_vc.c18
-rw-r--r--freebsd/lib/libc/rpc/getnetconfig.c40
-rw-r--r--freebsd/lib/libc/rpc/rpc_generic.c2
-rw-r--r--freebsd/lib/libc/rpc/rpcb_clnt.c4
-rw-r--r--rtemsbsd/fs/nfsclient/nfs.c926
-rw-r--r--rtemsbsd/rtems/rtems-kernel-vfs.c2
-rw-r--r--testsuite/nfs01/test_main.c5
-rw-r--r--waf_libbsd.py80
13 files changed, 1006 insertions, 109 deletions
diff --git a/buildset/default.ini b/buildset/default.ini
index 47df5ae4..454cc74e 100644
--- a/buildset/default.ini
+++ b/buildset/default.ini
@@ -60,7 +60,7 @@ pci = on
pf = on
regulator = on
rpc = on
-rpc_user = off
+rpc_user = on
rtems = on
tests = on
tty = on
diff --git a/config.inc b/config.inc
index 27863d5e..dd6938bf 100644
--- a/config.inc
+++ b/config.inc
@@ -1,6 +1,5 @@
NET_CFG_INTERFACE_0 = lo0
-NET_CFG_SELF_IP = 10.0.2.1
+NET_CFG_SELF_IP = 192.168.0.10
NET_CFG_NETMASK = 255.255.0.0
-NET_CFG_PEER_IP = 192.168.100.11
-NET_CFG_GATEWAY_IP = 192.168.100.11
-NET_CFG_NFS_MOUNT_PATH = 192.168.100.11:/srv/nfs
+NET_CFG_PEER_IP = 192.168.0.20
+NET_CFG_GATEWAY_IP = 192.168.0.1
diff --git a/freebsd/lib/libc/rpc/auth_unix.c b/freebsd/lib/libc/rpc/auth_unix.c
index ea8f44c9..3629fcc3 100644
--- a/freebsd/lib/libc/rpc/auth_unix.c
+++ b/freebsd/lib/libc/rpc/auth_unix.c
@@ -191,20 +191,27 @@ authunix_create_default(void)
gid_t gid;
gid_t *gids;
+#ifndef __rtems__
ngids_max = sysconf(_SC_NGROUPS_MAX) + 1;
gids = malloc(sizeof(gid_t) * ngids_max);
if (gids == NULL)
return (NULL);
+#endif /* __rtems__ */
if (gethostname(machname, sizeof machname) == -1)
abort();
machname[sizeof(machname) - 1] = 0;
uid = geteuid();
gid = getegid();
+#ifndef __rtems__
if ((ngids = getgroups(ngids_max, gids)) < 0)
abort();
if (ngids > NGRPS)
ngids = NGRPS;
+#else /* __rtems__ */
+ ngids = 0;
+ gids = NULL;
+#endif /* __rtems__ */
/* XXX: interface problem; we should translate from uid_t and gid_t */
auth = authunix_create(machname, uid, gid, ngids, gids);
free(gids);
diff --git a/freebsd/lib/libc/rpc/clnt_dg.c b/freebsd/lib/libc/rpc/clnt_dg.c
index 4ec2e8b0..70d94272 100644
--- a/freebsd/lib/libc/rpc/clnt_dg.c
+++ b/freebsd/lib/libc/rpc/clnt_dg.c
@@ -67,6 +67,12 @@ __FBSDID("$FreeBSD$");
#include "mt_misc.h"
+#ifdef __rtems__
+#undef thr_sigsetmask
+#define thr_sigsetmask(_a, _b, _c)
+#define cond_signal(_a)
+#define sigfillset(_a)
+#endif /* __rtems__ */
#ifdef _FREEFALL_CONFIG
/*
* Disable RPC exponential back-off for FreeBSD.org systems.
@@ -204,10 +210,12 @@ clnt_dg_create(int fd, const struct netbuf *svcaddr, rpcprog_t program,
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err1;
} else {
+#ifndef __rtems__
int i;
for (i = 0; i < dtbsize; i++)
cond_init(&dg_cv[i], 0, (void *) 0);
+#endif /* __rtems__ */
}
}
@@ -345,8 +353,10 @@ clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, void *argsp,
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
if (__isthreaded)
rpc_lock_value = 1;
else
@@ -630,8 +640,10 @@ clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
xdrs->x_op = XDR_FREE;
dummy = (*xdr_res)(xdrs, res_ptr);
mutex_unlock(&clnt_fd_lock);
@@ -658,8 +670,10 @@ clnt_dg_control(CLIENT *cl, u_int request, void *info)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+#endif * __rtems__ */
if (__isthreaded)
rpc_lock_value = 1;
else
@@ -800,8 +814,10 @@ clnt_dg_destroy(CLIENT *cl)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (dg_fd_locks[cu_fd])
cond_wait(&dg_cv[cu_fd], &clnt_fd_lock);
+#endif * __rtems__ */
if (cu->cu_closeit)
(void)_close(cu_fd);
if (cu->cu_kq >= 0)
@@ -852,4 +868,3 @@ time_not_ok(struct timeval *t)
return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
t->tv_usec < -1 || t->tv_usec > 1000000);
}
-
diff --git a/freebsd/lib/libc/rpc/clnt_generic.c b/freebsd/lib/libc/rpc/clnt_generic.c
index 5d1f7480..07a5258f 100644
--- a/freebsd/lib/libc/rpc/clnt_generic.c
+++ b/freebsd/lib/libc/rpc/clnt_generic.c
@@ -398,6 +398,11 @@ clnt_tli_create(int fd, const struct netconfig *nconf,
goto err1; /* borrow errors from clnt_dg/vc creates */
if (nconf) {
cl->cl_netid = strdup(nconf->nc_netid);
+#ifdef __rtems__
+ if (nconf->nc_device == NULL)
+ cl->cl_tp = "";
+ else
+#endif /* __rtems__ */
cl->cl_tp = strdup(nconf->nc_device);
} else {
cl->cl_netid = "";
diff --git a/freebsd/lib/libc/rpc/clnt_vc.c b/freebsd/lib/libc/rpc/clnt_vc.c
index 76ed41ff..96817d8f 100644
--- a/freebsd/lib/libc/rpc/clnt_vc.c
+++ b/freebsd/lib/libc/rpc/clnt_vc.c
@@ -85,6 +85,14 @@ __FBSDID("$FreeBSD$");
#include "rpc_com.h"
#include "mt_misc.h"
+#ifdef __rtems__
+#undef thr_sigsetmask
+#define thr_sigsetmask(_a, _b, _c)
+#define cond_signal(_a)
+#define sigfillset(_a)
+#define _sendmsg sendmsg
+#define _recvmsg recvmsg
+#endif /* __rtems__ */
#define MCALL_MSG_SIZE 24
struct cmessage {
@@ -219,10 +227,12 @@ clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog,
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err;
} else {
+#ifndef __rtems__
int i;
for (i = 0; i < dtbsize; i++)
cond_init(&vc_cv[i], 0, (void *) 0);
+#endif /* __rtems__ */
}
} else
assert(vc_cv != (cond_t *) NULL);
@@ -336,8 +346,10 @@ clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
if (__isthreaded)
rpc_lock_value = 1;
else
@@ -489,8 +501,10 @@ clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
xdrs->x_op = XDR_FREE;
dummy = (*xdr_res)(xdrs, res_ptr);
mutex_unlock(&clnt_fd_lock);
@@ -536,8 +550,10 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
if (__isthreaded)
rpc_lock_value = 1;
else
@@ -653,8 +669,10 @@ clnt_vc_destroy(CLIENT *cl)
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
+#ifndef __rtems__
while (vc_fd_locks[ct_fd])
cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
+#endif /* __rtems__ */
if (ct->ct_closeit && ct->ct_fd != -1) {
(void)_close(ct->ct_fd);
}
diff --git a/freebsd/lib/libc/rpc/getnetconfig.c b/freebsd/lib/libc/rpc/getnetconfig.c
index 63e80e26..4c66122d 100644
--- a/freebsd/lib/libc/rpc/getnetconfig.c
+++ b/freebsd/lib/libc/rpc/getnetconfig.c
@@ -63,7 +63,45 @@ __FBSDID("$FreeBSD$");
* used to specify the network transport to be used.
*/
-
+#ifdef __rtems__
+#undef fopen
+#undef fgets
+#undef fclose
+static const char *internal_netconfig[] = {
+ "udp6 tpi_clts v inet6 udp - -\n",
+ "tcp6 tpi_cots_ord v inet6 tcp - -\n",
+ "udp tpi_clts v inet udp - -\n",
+ "tcp tpi_cots_ord v inet tcp - -\n",
+ "rawip tpi_raw - inet - - -\n",
+ "local tpi_cots_ord - loopback - - -\n",
+ NULL
+};
+static int netconfig_next;
+static FILE*
+nc_fopen(const char* name, const char* mode) {
+ netconfig_next = 0;
+ return (FILE*) &netconfig_next;
+}
+static int
+nc_fclose(FILE *stream) {
+ return 0;
+}
+static char *
+nc_fgets(char * str, int size, FILE *stream) {
+ int l;
+ const char *p = internal_netconfig[netconfig_next];;
+ if (p == NULL)
+ return NULL;
+ l = strlen(p);
+ size = l < size ? l : size;
+ memcpy(str, p, size);
+ ++netconfig_next;
+ return str;
+}
+#define fopen nc_fopen
+#define fgets nc_fgets
+#define fclose nc_fclose
+#endif /* __rtems__ */
/*
* netconfig errors
*/
diff --git a/freebsd/lib/libc/rpc/rpc_generic.c b/freebsd/lib/libc/rpc/rpc_generic.c
index 9a72dacc..a634a810 100644
--- a/freebsd/lib/libc/rpc/rpc_generic.c
+++ b/freebsd/lib/libc/rpc/rpc_generic.c
@@ -122,9 +122,11 @@ __rpc_dtbsize(void)
if (tbsize) {
return (tbsize);
}
+#ifndef __rtems__
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
return (tbsize = (int)rl.rlim_max);
}
+#endif /* __rtems__ */
/*
* Something wrong. I'll try to save face by returning a
* pessimistic number.
diff --git a/freebsd/lib/libc/rpc/rpcb_clnt.c b/freebsd/lib/libc/rpc/rpcb_clnt.c
index 88717a36..a351c184 100644
--- a/freebsd/lib/libc/rpc/rpcb_clnt.c
+++ b/freebsd/lib/libc/rpc/rpcb_clnt.c
@@ -361,7 +361,11 @@ getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr)
return (client);
}
} else {
+#ifndef __rtems__
if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
+#else /* __rtems__ */
+ if (getaddrinfo(host, "111", &hints, &res) != 0) {
+#endif /* __rtems__ */
rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
return NULL;
}
diff --git a/rtemsbsd/fs/nfsclient/nfs.c b/rtemsbsd/fs/nfsclient/nfs.c
index b2526195..fe8d8412 100644
--- a/rtemsbsd/fs/nfsclient/nfs.c
+++ b/rtemsbsd/fs/nfsclient/nfs.c
@@ -53,70 +53,872 @@
#include <sys/time.h>
#include <sys/vnode.h>
+#include <rpc/rpc.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <rpc/types.h>
+#include <rpc/auth.h>
+
#include <fs/nfsclient/nfs.h>
#include <nfs/nfsproto.h>
#include <nfsclient/nfs.h>
#include <rtems/bsd/rootfs.h>
+
#include <stdio.h>
SYSINIT_MODULE_REFERENCE(rootfs);
SYSINIT_MODULE_REFERENCE(nfs);
#ifndef RTEMS_DEBUG
-#define RTEMS_DEBUG 0
+#define RTEMS_DEBUG 1
+#endif
+#ifndef RTEMS_NFSCL_DEBUGLEVEL
+#define RTEMS_NFSCL_DEBUGLEVEL 0
#endif
-#if RTEMS_DEBUG
+#if RTEMS_NFSCL_DEBUGLEVEL
extern int nfscl_debuglevel;
#endif
+/*
+ * Map user to kernel or just provide
+ */
+#define NFS_PROGRAM NFS_PROG
+#define MOUNTPROG 100005
+#define MOUNTPROC_MNT 1
+#define MNTPATHLEN 1024
+
+#define NFS_FHSIZE NFSX_V2FH
+#define NFS3_FHSIZE NFSX_V3FHMAX
+
+#undef malloc
+#undef free
+
+/* Table for af,sotype -> netid conversions. */
+static const struct nc_protos {
+ const char *netid;
+ int af;
+ int sotype;
+} nc_protos[] = {
+ {"udp", AF_INET, SOCK_DGRAM},
+ {"tcp", AF_INET, SOCK_STREAM},
+ {"udp6", AF_INET6, SOCK_DGRAM},
+ {"tcp6", AF_INET6, SOCK_STREAM},
+ {NULL, 0, 0}
+};
+
+struct nfhret {
+ u_long stat;
+ long vers;
+ long auth;
+ long fhsize;
+ u_char nfh[NFS3_FHSIZE];
+};
+
+enum mountmode {
+ ANY,
+ V2,
+ V3,
+ V4
+};
+
+/* Return codes for nfs_tryproto. */
+enum tryret {
+ TRYRET_SUCCESS,
+ TRYRET_TIMEOUT, /* No response received. */
+ TRYRET_REMOTEERR, /* Error received from remote server. */
+ TRYRET_LOCALERR /* Local failure. */
+};
+
+/*
+ * Taken from freebsd/sbin/mount_nfs/mount_nfs.c
+ */
+struct nfs_args {
+ struct mntarg *ma;
+ char options[256 + 1];
+ char hostname[MNAMELEN + 1];
+ char dirpath[MNAMELEN + 1];
+ char hname[MAXHOSTNAMELEN + 5];
+ char pname[MAXHOSTNAMELEN + 5];
+ enum mountmode mountmode;
+ int opflags;
+ int mnttcp_ok;
+ int vers;
+ int nfsproto;
+ char portspec[16];
+ int noconn;
+ struct sockaddr *addr;
+ int addrlen;
+ u_char *fh;
+ int fhsize;
+ int secflavor;
+ int got_principal;
+ struct addrinfo *ai_nfs;
+ char errstr[256];
+};
+#define OF_NOINET4 4
+#define OF_NOINET6 8
+
+/*
+ * Options to exclude from the mount
+ */
+static const char *opts_exclude[] = {
+ "nfsv2",
+ "nfsv3",
+ "nfsv4",
+ "port",
+ "noinet4",
+ "noinet6",
+ "vers"
+};
+#define NUM_OPTS_EXCLUDES (sizeof(opts_exclude) / sizeof(opts_exclude[0]))
+
+static void
+nfs_args_defaults(struct nfs_args *args)
+{
+ memset(args, 0, sizeof(struct nfs_args));
+ args->ma = NULL;
+ args->mountmode = ANY;
+ args->vers = 4;
+ args->opflags = 0;
+ args->nfsproto = IPPROTO_TCP;
+ args->mnttcp_ok = 1;
+ args->noconn = 0;
+ args->addrlen = 0;
+ args->fh = NULL;
+ args->fhsize = 0;
+ args->secflavor = -1;
+ args->got_principal = 0;
+}
+
+/* The header for the mount arguments */
+struct mntarg {
+ struct iovec *v;
+ int len;
+ int error;
+ SLIST_HEAD(, mntaarg) list;
+};
+
+static void
+print_mount_args(struct mntarg *ma)
+{
+ if (RTEMS_DEBUG) {
+ int m;
+ printf("nfs: mount args: %d\n", ma->len / 2);
+ for (m = 0; m < ma->len; m += 2) {
+ bool string = true;
+ const char *p;
+ printf(" %3d %s%c", ma->v[m + 1].iov_len,
+ (char*) ma->v[m].iov_base,
+ ma->v[m + 1].iov_len == 0 ? ' ' : '=');
+ p = (const char*) ma->v[m + 1].iov_base;
+ while (p != NULL && *p != '\0') {
+ if (*p < ' ' || *p > '~') {
+ string = false;
+ break;
+ }
+ ++p;
+ }
+ p = (const char*) ma->v[m + 1].iov_base;
+ if (p != NULL && string) {
+ printf(p);
+ } else if (p != NULL) {
+ int i;
+ for (i = 0; i < ma->v[m + 1].iov_len; ++i) {
+ printf("%02x ", (int) *p);
+ ++p;
+ }
+ }
+ printf("\n");
+ }
+ }
+}
+
+/*
+ * Look up a netid based on an address family and socket type.
+ * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM.
+ *
+ * XXX there should be a library function for this.
+ */
+static const char *
+netidbytype(int af, int sotype)
+{
+ struct nc_protos *p;
+ for (p = nc_protos; p->netid != NULL; p++) {
+ if (af != p->af || sotype != p->sotype)
+ continue;
+ return (p->netid);
+ }
+ return (NULL);
+}
+
+static const char *
+sec_num_to_name(int flavor)
+{
+ switch (flavor) {
+ case RPCSEC_GSS_KRB5:
+ return ("krb5");
+ case RPCSEC_GSS_KRB5I:
+ return ("krb5i");
+ case RPCSEC_GSS_KRB5P:
+ return ("krb5p");
+ case AUTH_SYS:
+ return ("sys");
+ }
+ return (NULL);
+}
+
+/*
+ * Catagorise a RPC return status and error into an `enum tryret'
+ * return code.
+ */
+static enum tryret
+returncode(enum clnt_stat clntstat, struct rpc_err *rpcerr)
+{
+
+ switch (clntstat) {
+ case RPC_TIMEDOUT:
+ return (TRYRET_TIMEOUT);
+ case RPC_PMAPFAILURE:
+ case RPC_PROGNOTREGISTERED:
+ case RPC_PROGVERSMISMATCH:
+ /* XXX, these can be local or remote. */
+ case RPC_CANTSEND:
+ case RPC_CANTRECV:
+ return (TRYRET_REMOTEERR);
+ case RPC_SYSTEMERROR:
+ switch (rpcerr->re_errno) {
+ case ETIMEDOUT:
+ return (TRYRET_TIMEOUT);
+ case ENOMEM:
+ break;
+ default:
+ return (TRYRET_REMOTEERR);
+ }
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ return (TRYRET_LOCALERR);
+}
+
+/*
+ * Look up a netconfig entry based on a netid, and cache the result so
+ * that we don't need to remember to call freenetconfigent().
+ *
+ * Otherwise it behaves just like getnetconfigent(), so nc_*error()
+ * work on failure.
+ */
+static struct netconfig *
+getnetconf_cached(const char *netid)
+{
+ static struct nc_entry {
+ struct netconfig *nconf;
+ struct nc_entry *next;
+ } *head;
+ struct nc_entry *p;
+ struct netconfig *nconf;
+
+ for (p = head; p != NULL; p = p->next)
+ if (strcmp(netid, p->nconf->nc_netid) == 0)
+ return (p->nconf);
+
+ if ((nconf = getnetconfigent(netid)) == NULL)
+ return (NULL);
+ if ((p = malloc(sizeof(*p))) == NULL)
+ err(1, "malloc");
+ p->nconf = nconf;
+ p->next = head;
+ head = p;
+
+ return (p->nconf);
+}
+
+/*
+ * xdr routines for mount rpc's
+ */
+static int
+xdr_dir(XDR *xdrsp, char *dirp)
+{
+ return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
+}
+
+static int
+xdr_fh(XDR *xdrsp, struct nfhret *np)
+{
+ int i;
+ long auth, authcnt, authfnd = 0;
+
+ if (!xdr_u_long(xdrsp, &np->stat))
+ return (0);
+ if (np->stat)
+ return (1);
+ switch (np->vers) {
+ case 1:
+ np->fhsize = NFS_FHSIZE;
+ return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFS_FHSIZE));
+ case 3:
+ if (!xdr_long(xdrsp, &np->fhsize))
+ return (0);
+ if (np->fhsize <= 0 || np->fhsize > NFS3_FHSIZE)
+ return (0);
+ if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
+ return (0);
+ if (!xdr_long(xdrsp, &authcnt))
+ return (0);
+ for (i = 0; i < authcnt; i++) {
+ if (!xdr_long(xdrsp, &auth))
+ return (0);
+ if (np->auth == -1) {
+ np->auth = auth;
+ authfnd++;
+ } else if (auth == np->auth) {
+ authfnd++;
+ }
+ }
+ /*
+ * Some servers, such as DEC's OSF/1 return a nil authenticator
+ * list to indicate RPCAUTH_UNIX.
+ */
+ if (authcnt == 0 && np->auth == -1)
+ np->auth = AUTH_SYS;
+ if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS))
+ np->stat = EAUTH;
+ return (1);
+ }
+ return (0);
+}
+
+static int
+getnfsargs(char *spec, struct nfs_args *args)
+{
+ struct addrinfo hints;
+ int ecode, speclen, remoteerr, offset, have_bracket = 0;
+ char *hostp, *delimp, *errstr;
+ size_t len;
+
+ if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
+ *(delimp + 1) == ':') {
+ hostp = spec + 1;
+ spec = delimp + 2;
+ have_bracket = 1;
+ } else if ((delimp = strrchr(spec, ':')) != NULL) {
+ hostp = spec;
+ spec = delimp + 1;
+ } else {
+ if (RTEMS_DEBUG) {
+ printf("nfs: mount: no <host>:<dirpath> nfs-name\n");
+ }
+ return (-1);
+ }
+ *delimp = '\0';
+
+ /*
+ * If there has been a trailing slash at mounttime it seems
+ * that some mountd implementations fail to remove the mount
+ * entries from their mountlist while unmounting.
+ */
+ for (speclen = strlen(spec);
+ speclen > 1 && spec[speclen - 1] == '/';
+ speclen--)
+ spec[speclen - 1] = '\0';
+ if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
+ if (RTEMS_DEBUG) {
+ printf("nfs: mount: %s:%s: %s", hostp, spec, strerror(ENAMETOOLONG));
+ }
+ return (-1);
+ }
+ /* Make both '@' and ':' notations equal */
+ if (*hostp != '\0') {
+ len = strlen(hostp);
+ offset = 0;
+ if (have_bracket)
+ args->hostname[offset++] = '[';
+ memmove(args->hostname + offset, hostp, len);
+ if (have_bracket)
+ args->hostname[len + offset++] = ']';
+ args->hostname[len + offset++] = ':';
+ memmove(args->hostname + len + offset, spec, speclen);
+ args->hostname[len + speclen + offset] = '\0';
+ }
+
+ /*
+ * Handle an internet host address.
+ */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_NUMERICHOST;
+ if (args->nfsproto == IPPROTO_TCP)
+ hints.ai_socktype = SOCK_STREAM;
+ else if (args->nfsproto == IPPROTO_UDP)
+ hints.ai_socktype = SOCK_DGRAM;
+
+ char* portspec = args->portspec[0] == '\0' ? NULL : args->portspec;
+ if (getaddrinfo(hostp, portspec, &hints, &args->ai_nfs) != 0) {
+ hints.ai_flags = AI_CANONNAME;
+ if ((ecode = getaddrinfo(hostp, args->portspec, &hints, &args->ai_nfs))
+ != 0) {
+ if (RTEMS_DEBUG) {
+ printf("nfs: mount: getaddrinfo: ");
+ if (args->portspec[0] == '\0')
+ printf("%s: %s\n", hostp, gai_strerror(ecode));
+ else
+ printf("%s:%s: %s]n", hostp, args->portspec,
+ gai_strerror(ecode));
+ }
+ return (-1);
+ }
+
+ /*
+ * For a Kerberized nfs mount where the "principal"
+ * argument has not been set, add it here.
+ */
+ if (args->got_principal == 0 && args->secflavor != AUTH_SYS &&
+ args->ai_nfs->ai_canonname != NULL) {
+ snprintf(args->pname, sizeof(args->pname), "nfs@%s",
+ args->ai_nfs->ai_canonname);
+ }
+ }
+
+ strlcpy(args->hname, hostp, sizeof(args->hname));
+ strlcpy(args->dirpath, spec, sizeof(args->dirpath));
+
+ return (0);
+}
+
+/*
+ * Try to set up the NFS arguments according to the address
+ * family, protocol (and possibly port) specified in `ai'.
+ *
+ * Returns TRYRET_SUCCESS if successful, or:
+ * TRYRET_TIMEOUT The server did not respond.
+ * TRYRET_REMOTEERR The server reported an error.
+ * TRYRET_LOCALERR Local failure.
+ *
+ * In all error cases, *errstr will be set to a statically-allocated string
+ * describing the error.
+ */
+static enum tryret
+nfs_tryproto(struct addrinfo *ai, struct nfs_args *args)
+{
+ #define errbuf args->errstr
+ struct sockaddr_storage nfs_ss;
+ struct netbuf nfs_nb;
+ struct nfhret nfhret;
+ struct timeval try;
+ struct rpc_err rpcerr;
+ CLIENT *clp;
+ struct netconfig *nconf, *nconf_mnt;
+ const char *netid, *netid_mnt, *secname;
+ int doconnect, nfsvers, mntvers, sotype;
+ enum clnt_stat clntstat;
+ enum mountmode trymntmode;
+
+ const char *portspec = *args->portspec == '\0' ? NULL : args->portspec;
+ const char *hostp = args->hname;
+ const char *spec = args->dirpath;
+
+ sotype = 0;
+ trymntmode = args->mountmode;
+ errbuf[0] = '\0';
+
+ if (args->nfsproto == IPPROTO_TCP)
+ sotype = SOCK_STREAM;
+ else if (args->nfsproto == IPPROTO_UDP)
+ sotype = SOCK_DGRAM;
+
+ if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) {
+ snprintf(errbuf, sizeof errbuf,
+ "af %d sotype %d not supported", ai->ai_family, sotype);
+ return (TRYRET_LOCALERR);
+ }
+ if ((nconf = getnetconf_cached(netid)) == NULL) {
+ snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror());
+ return (TRYRET_LOCALERR);
+ }
+ /* The RPCPROG_MNT netid may be different. */
+ if (args->mnttcp_ok) {
+ netid_mnt = netid;
+ nconf_mnt = nconf;
+ } else {
+ if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM))
+ == NULL) {
+ snprintf(errbuf, sizeof errbuf,
+ "af %d sotype SOCK_DGRAM not supported",
+ ai->ai_family);
+ return (TRYRET_LOCALERR);
+ }
+ if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) {
+ snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt,
+ nc_sperror());
+ return (TRYRET_LOCALERR);
+ }
+ }
+
+tryagain:
+ if (trymntmode == V4) {
+ nfsvers = 4;
+ mntvers = 3; /* Workaround for GCC. */
+ } else if (trymntmode == V2) {
+ nfsvers = 2;
+ mntvers = 1;
+ } else {
+ nfsvers = 3;
+ mntvers = 3;
+ }
+
+ if (portspec != NULL) {
+ /* `ai' contains the complete nfsd sockaddr. */
+ nfs_nb.buf = ai->ai_addr;
+ nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen;
+ } else {
+ /* Ask the remote rpcbind. */
+ nfs_nb.buf = &nfs_ss;
+ nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss;
+
+ if (!rpcb_getaddr(NFS_PROGRAM, nfsvers, nconf, &nfs_nb,
+ hostp)) {
+ if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH &&
+ trymntmode == ANY) {
+ trymntmode = V2;
+ goto tryagain;
+ }
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s",
+ netid, hostp, spec,
+ clnt_spcreateerror("RPCPROG_NFS"));
+ return (returncode(rpc_createerr.cf_stat,
+ &rpc_createerr.cf_error));
+ }
+ }
+
+ /* Check that the server (nfsd) responds on the port we have chosen. */
+ clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, NFS_PROGRAM, nfsvers,
+ 0, 0);
+ if (clp == NULL) {
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid,
+ hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS"));
+ return (returncode(rpc_createerr.cf_stat,
+ &rpc_createerr.cf_error));
+ }
+ if (sotype == SOCK_DGRAM && args->noconn == 0) {
+ /*
+ * Use connect(), to match what the kernel does. This
+ * catches cases where the server responds from the
+ * wrong source address.
+ */
+ doconnect = 1;
+ if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) {
+ clnt_destroy(clp);
+ snprintf(errbuf, sizeof errbuf,
+ "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp,
+ spec);
+ return (TRYRET_LOCALERR);
+ }
+ }
+
+ try.tv_sec = 10;
+ try.tv_usec = 0;
+ clntstat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_void, NULL, try);
+ if (clntstat != RPC_SUCCESS) {
+ if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
+ clnt_destroy(clp);
+ trymntmode = V2;
+ goto tryagain;
+ }
+ clnt_geterr(clp, &rpcerr);
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid,
+ hostp, spec, clnt_sperror(clp, "NFSPROC_NULL"));
+ clnt_destroy(clp);
+ return (returncode(clntstat, &rpcerr));
+ }
+ clnt_destroy(clp);
+
+ /*
+ * For NFSv4, there is no mount protocol.
+ */
+ if (trymntmode == V4) {
+ /*
+ * Store the server address in nfsargsp, making
+ * sure to copy any locally allocated structures.
+ */
+ args->addrlen = nfs_nb.len;
+ args->addr = malloc(args->addrlen);
+ if (args->addr == NULL) {
+ snprintf(errbuf, sizeof errbuf, "no memory");
+ return (TRYRET_LOCALERR);
+ }
+ bcopy(nfs_nb.buf, args->addr, args->addrlen);
+ args->ma = mount_arg(args->ma, "addr", args->addr, args->addrlen);
+ secname = sec_num_to_name(args->secflavor);
+ if (secname != NULL) {
+ args->ma = mount_arg(args->ma, "sec",
+ __DECONST(void *, secname), (size_t)-1);
+ }
+ args->ma = mount_arg(args->ma, "nfsv4", NULL, 0);
+ args->ma = mount_arg(args->ma, "dirpath", spec, -1);
+
+ return (TRYRET_SUCCESS);
+ }
+
+ /* Send the MOUNTPROC_MNT RPC to get the root filehandle. */
+ try.tv_sec = 10;
+ try.tv_usec = 0;
+ clp = clnt_tp_create(hostp, MOUNTPROG, mntvers, nconf_mnt);
+ if (clp == NULL) {
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
+ hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create"));
+ return (returncode(rpc_createerr.cf_stat,
+ &rpc_createerr.cf_error));
+ }
+ clp->cl_auth = authsys_create_default();
+ nfhret.auth = args->secflavor;
+ nfhret.vers = mntvers;
+ clntstat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec,
+ (xdrproc_t)xdr_fh, &nfhret, try);
+ auth_destroy(clp->cl_auth);
+ if (clntstat != RPC_SUCCESS) {
+ if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
+ clnt_destroy(clp);
+ trymntmode = V2;
+ goto tryagain;
+ }
+ clnt_geterr(clp, &rpcerr);
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
+ hostp, spec, clnt_sperror(clp, "RPCPROG_MNT"));
+ clnt_destroy(clp);
+ return (returncode(clntstat, &rpcerr));
+ }
+ clnt_destroy(clp);
+
+ if (nfhret.stat != 0) {
+ snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
+ hostp, spec, strerror(nfhret.stat));
+ return (TRYRET_REMOTEERR);
+ }
+
+ /*
+ * Store the filehandle and server address in nfsargsp, making
+ * sure to copy any locally allocated structures.
+ */
+ args->addrlen = nfs_nb.len;
+ args->addr = malloc(args->addrlen);
+ args->fhsize = nfhret.fhsize;
+ args->fh = malloc(args->fhsize);
+ if (args->addr == NULL || args->fh == NULL) {
+ free(args->addr);
+ free(args->fh);
+ snprintf(errbuf, sizeof errbuf, "no memory");
+ return (TRYRET_LOCALERR);
+ }
+ bcopy(nfs_nb.buf, args->addr, args->addrlen);
+ bcopy(nfhret.nfh, args->fh, args->fhsize);
+
+ args->ma = mount_arg(args->ma, "addr", args->addr, args->addrlen);
+ args->ma = mount_arg(args->ma, "fh", args->fh, args->fhsize);
+ secname = sec_num_to_name(nfhret.auth);
+ if (secname) {
+ args->ma = mount_arg(args->ma, "sec",
+ __DECONST(void *, secname), (size_t)-1);
+ }
+ if (nfsvers == 3)
+ args->ma = mount_arg(args->ma, "nfsv3", NULL, 0);
+
+ return (TRYRET_SUCCESS);
+}
+
+static int
+nfs_trymount(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ struct addrinfo *ai, struct nfs_args *args,
+ const char* fspath, void *data
+) {
+ struct thread *td = curthread;
+ char errmsg[255];
+ int error;
+ if (td == NULL) {
+ if (RTEMS_DEBUG)
+ printf("nfs: mount: no current thread\n");
+ return ENOMEM;
+ }
+ args->ma = mount_arg(
+ args->ma, "fstype", RTEMS_DECONST(char *, mt_entry->type), -1);
+ args->ma = mount_arg(args->ma, "fspath", RTEMS_DECONST(char *, fspath), -1);
+ args->ma = mount_arg(
+ args->ma, "hostname", RTEMS_DECONST(char *, args->hostname), -1);
+ if (mt_entry->writeable) {
+ args->ma = mount_arg(args->ma, "rw", NULL, 0);
+ } else {
+ args->ma = mount_arg(args->ma, "ro", NULL, 0);
+ }
+ if (data != NULL) {
+ char *options = args->options;
+ char *opts;
+ /*
+ * See `man mount_nfs` and the list of options.
+ */
+ strlcpy(options, (const char *)data, sizeof(args->options));
+ opts = &options[0];
+ while (opts != NULL) {
+ char *delimiter = strchr(opts, ',');
+ char *opt = opts;
+ int s;
+ if (delimiter != NULL) {
+ *delimiter = '\0';
+ opts = delimiter + 1;
+ } else {
+ opts = NULL;
+ }
+ delimiter = strchr(opt, '=');
+ if (delimiter != NULL) {
+ *delimiter = '\0';
+ }
+ for (s = 0; s < NUM_OPTS_EXCLUDES; ++s) {
+ if (strcasecmp(opt, opts_exclude[s]) == 0) {
+ break;
+ }
+ }
+ if (s < NUM_OPTS_EXCLUDES) {
+ continue;
+ }
+ if (delimiter != NULL) {
+ args->ma = mount_arg(
+ args->ma, opt, delimiter + 1, -1);
+ } else {
+ args->ma = mount_arg(args->ma, opt, NULL, 0);
+ }
+ }
+ }
+ memset(errmsg, 0, sizeof(errmsg));
+ print_mount_args(args->ma);
+ args->ma = mount_arg(args->ma, "errmsg", errmsg, sizeof(errmsg) - 1);
+ error = kernel_mount(args->ma, MNT_VERIFIED);
+ if (error == 0) {
+ struct nameidata nd;
+ vhold(rootvnode);
+ NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE,
+ fspath, rootvnode, td);
+ error = namei(&nd);
+ if (error == 0) {
+ rtems_bsd_libio_loc_set_vnode(
+ &mt_entry->mt_fs_root->location, nd.ni_vp);
+ rtems_bsd_vfs_clonenode(
+ &mt_entry->mt_fs_root->location);
+ NDFREE(&nd, NDF_NO_VP_RELE);
+ } else {
+ NDFREE(&nd, 0);
+ rtems_bsd_libio_loc_set_vnode(
+ &mt_entry->mt_fs_root->location, NULL);
+ rtems_bsd_vfs_freenode(
+ &mt_entry->mt_fs_root->location);
+ rtems_bsd_rootfs_rmdir(fspath);
+ }
+ } else {
+ if (RTEMS_DEBUG) {
+ if (strlen(errmsg) > 0) {
+ printf("nfs: mount: error: %s\n", errmsg);
+ }
+ }
+ }
+ return error;
+}
+
int
rtems_nfs_initialize(
rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
{
- struct thread *td = curthread;
+ struct nfs_args args;
const char *fspath = NULL;
- char options[64];
char *at;
int error;
if (RTEMS_DEBUG) {
- printf("nfsv4: mount: %s -> %s", mt_entry->type, mt_entry->dev,
+ printf("nfs: mount: %s -> %s", mt_entry->type, mt_entry->dev,
mt_entry->target);
if (data != NULL) {
printf(" (%s)", (const char *)data);
}
printf("\n");
-#ifdef RTEMS_NFSCL_DEBUGLEVEL
+#if RTEMS_NFSCL_DEBUGLEVEL
nfscl_debuglevel = RTEMS_NFSCL_DEBUGLEVEL;
#endif
}
- if (td == NULL) {
- if (RTEMS_DEBUG)
- printf("nfsv4: mount: no current thread\n");
- error = ENOMEM;
- goto out;
- }
-
at = strchr(mt_entry->dev, '@');
if (at != NULL) {
if (RTEMS_DEBUG)
printf(
- "nfsv4: mount: user/group name in path not supported\n");
+ "nfs: mount: user/group name in path not supported\n");
error = EINVAL;
goto out;
}
+ nfs_args_defaults(&args);
+
if (data != NULL) {
+ char options[64];
size_t opts_len = strnlen((const char *)data, sizeof(options));
+ char *opts;
if (opts_len >= sizeof(options)) {
if (RTEMS_DEBUG)
printf(
- "nfsv4: mount: options string too long\n");
+ "nfs: mount: options string too long\n");
error = EINVAL;
goto out;
}
+
+ /*
+ * See `man mount_nfs` and the list of options.
+ */
+ strlcpy(options, (const char *)data, sizeof(options));
+ opts = &options[0];
+ while (opts != NULL) {
+ char *delimiter = strchr(opts, ',');
+ char *opt = opts;
+ if (delimiter != NULL) {
+ *delimiter = '\0';
+ opts = delimiter + 1;
+ } else {
+ opts = NULL;
+ }
+ delimiter = strchr(opt, '=');
+ if (strcasecmp(opt, "nfsv2") == 0) {
+ args.vers = 2;
+ args.mountmode = V2;
+ } else if (strcasecmp(opt, "nfsv3") == 0) {
+ args.vers = 3;
+ args.mountmode = V3;
+ } else if (strcasecmp(opt, "nfsv4") == 0) {
+ args.vers = 4;
+ args.mountmode = V4;
+ if (args.portspec[0] == '\0')
+ strlcpy(args.portspec, "2049", sizeof(args.portspec));
+ } else if (strcasecmp(opt, "tcp") == 0) {
+ args.nfsproto = IPPROTO_TCP;
+ } else if (strcasecmp(opt, "udp") == 0) {
+ args.nfsproto = IPPROTO_UDP;
+ } else if (strcasecmp(opt, "port") == 0) {
+ if (delimiter != NULL) {
+ strlcpy(args.portspec, delimiter + 1, sizeof(args.portspec));
+ } else {
+ error = EINVAL;
+ goto out;
+ }
+ } else if (strcasecmp(opt, "noinet4") == 0) {
+ args.opflags |= OF_NOINET4;
+ } else if (strcasecmp(opt, "noinet6") == 0) {
+ args.opflags |= OF_NOINET6;
+ } else if (strcasecmp(opt, "vers") == 0) {
+ if (delimiter != NULL) {
+ args.vers = 2;
+ } else {
+ error = EINVAL;
+ goto out;
+ }
+ }
+ }
}
rtems_bsd_vfs_mount_init(mt_entry);
@@ -130,6 +932,14 @@ rtems_nfs_initialize(
goto out;
}
+ if (getnfsargs(mt_entry->dev, &args) < 0) {
+ if (RTEMS_DEBUG)
+ printf(
+ "nfs: mount: invalid device path: %s\n", mt_entry->dev);
+ error = EINVAL;
+ goto out;
+ }
+
rtems_bsd_libio_loc_set_vnode(&mt_entry->mt_fs_root->location, NULL);
rtems_bsd_libio_loc_set_vnode_dir(
&mt_entry->mt_fs_root->location, NULL);
@@ -141,79 +951,35 @@ rtems_nfs_initialize(
*/
error = rtems_bsd_rootfs_mkdir(fspath);
if (error == 0) {
- struct mntarg *ma = NULL;
- char errmsg[255];
- ma = mount_arg(
- ma, "fstype", RTEMS_DECONST(char *, mt_entry->type), -1);
- ma = mount_arg(ma, "fspath", RTEMS_DECONST(char *, fspath), -1);
- ma = mount_arg(
- ma, "from", RTEMS_DECONST(char *, mt_entry->dev), -1);
- if (mt_entry->writeable) {
- ma = mount_arg(ma, "rw", NULL, 0);
- } else {
- ma = mount_arg(ma, "ro", NULL, 0);
- }
- if (data != NULL) {
- char *opts;
- /*
- * See `man mount_nfs` and the list of options.
- */
- strlcpy(options, (const char *)data, sizeof(options));
- opts = &options[0];
- while (opts != NULL) {
- char *delimiter = strchr(opts, ',');
- char *opt = opts;
- if (delimiter != NULL) {
- *delimiter = '\0';
- opts = delimiter + 1;
- } else {
- opts = NULL;
- }
- delimiter = strchr(opt, '=');
- if (delimiter != NULL) {
- *delimiter = '\0';
- ma = mount_arg(
- ma, opt, delimiter + 1, -1);
- } else {
- ma = mount_arg(ma, opt, NULL, 0);
- }
- }
- }
- memset(errmsg, 0, sizeof(errmsg));
- ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg) - 1);
- error = kernel_mount(ma, MNT_VERIFIED);
- if (error == 0) {
- struct nameidata nd;
- vhold(rootvnode);
- NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE,
- fspath, rootvnode, td);
- error = namei(&nd);
- if (error == 0) {
- rtems_bsd_libio_loc_set_vnode(
- &mt_entry->mt_fs_root->location, nd.ni_vp);
- rtems_bsd_vfs_clonenode(
- &mt_entry->mt_fs_root->location);
- NDFREE(&nd, NDF_NO_VP_RELE);
- } else {
- NDFREE(&nd, 0);
- rtems_bsd_libio_loc_set_vnode(
- &mt_entry->mt_fs_root->location, NULL);
- rtems_bsd_vfs_freenode(
- &mt_entry->mt_fs_root->location);
- rtems_bsd_rootfs_rmdir(fspath);
- }
- } else {
+ struct addrinfo *ai;
+ enum tryret tryret;
+ for (ai = args.ai_nfs; ai != NULL; ai = ai->ai_next) {
+ if ((ai->ai_family == AF_INET6) &&
+ (args.opflags & OF_NOINET6))
+ continue;
+ if ((ai->ai_family == AF_INET) &&
+ (args.opflags & OF_NOINET4))
+ continue;
+ tryret = nfs_tryproto(ai, &args);
+ if (tryret == TRYRET_SUCCESS) {
+ error = nfs_trymount(mt_entry, ai, &args, fspath, data);
if (RTEMS_DEBUG)
- printf("nfsv4: mount: error: %s\n", errmsg);
+ printf("nfs: mount: (%d) %s\n", error, strerror(error));
+ break;
+ } else {
+ error = EIO;
+ if (RTEMS_DEBUG)
+ printf("nfs: mount: %s\n", args.errstr);
}
}
+ }
+
+ freeaddrinfo(args.ai_nfs);
rtems_bsd_libio_loc_set_vnode_dir(
&mt_entry->mt_fs_root->location, NULL);
out:
- if (RTEMS_DEBUG)
- printf("nfsv4: mount: (%d) %s\n", error, strerror(error));
if (error != 0) {
if (fspath != NULL) {
rtems_bsd_rootfs_rmdir(fspath);
diff --git a/rtemsbsd/rtems/rtems-kernel-vfs.c b/rtemsbsd/rtems/rtems-kernel-vfs.c
index d5729bfb..c387271b 100644
--- a/rtemsbsd/rtems/rtems-kernel-vfs.c
+++ b/rtemsbsd/rtems/rtems-kernel-vfs.c
@@ -185,7 +185,7 @@ rtems_bsd_vfs_vnode_componentname(struct componentname *cnd, struct vnode *vp,
name[namemax] = '\0';
namelen = namemax;
tvp = vp;
- error = vn_vptocnp(&tvp, NULL, name, &namelen);
+ error = vn_vptocnp(&tvp, cred, name, &namelen);
if (error == 0) {
name = &name[namelen];
namelen = namemax - namelen;
diff --git a/testsuite/nfs01/test_main.c b/testsuite/nfs01/test_main.c
index 21f64d11..a6cb91f3 100644
--- a/testsuite/nfs01/test_main.c
+++ b/testsuite/nfs01/test_main.c
@@ -53,6 +53,7 @@
#define TEST_NAME "LIBBSD NFS 1"
#define TEST_STATE_USER_INPUT 1
+#define TEST_WAIT_FOR_LINK NET_CFG_INTERFACE_0
static const char *test_top = "test-nfs01";
@@ -323,10 +324,12 @@ test_path_eval(const char *base, int depth)
static void
test_nfs(const char *base)
{
- test_printer_data pd;
test_path_eval(base, 5);
+#if NFS_TREE_WALK
+ test_printer_data pd;
memset(&pd, 0, sizeof(pd));
test_walk_tree(base, test_walk_tree_printer, &pd);
+#endif
}
static void
diff --git a/waf_libbsd.py b/waf_libbsd.py
index b18077cf..97e6d6ee 100644
--- a/waf_libbsd.py
+++ b/waf_libbsd.py
@@ -287,40 +287,80 @@ class Builder(builder.ModuleManager):
if not os.path.exists(bld.env.NET_CONFIG):
bld.fatal('network configuraiton \'%s\' not found' %
(bld.env.NET_CONFIG))
- tags = [
- 'NET_CFG_INTERFACE_0', 'NET_CFG_SELF_IP', 'NET_CFG_NETMASK',
- 'NET_CFG_PEER_IP', 'NET_CFG_GATEWAY_IP', 'NET_CFG_NFS_MOUNT_PATH',
- 'NET_CFG_NFS_MOUNT_OPTIONS'
- ]
+ net_cfg = {
+ 'NET_CFG_INTERFACE_0': { 'mandatory': True, },
+ 'NET_CFG_SELF_IP': { 'mandatory': True },
+ 'NET_CFG_NETMASK': { 'mandatory': True },
+ 'NET_CFG_PEER_IP': { 'mandatory': True },
+ 'NET_CFG_GATEWAY_IP': { 'manditory': True },
+ 'NET_CFG_NFS_MOUNT_PATH': { 'mandatory': False,
+ 'default': '@NET_CFG_PEER_IP@/rtems' },
+ 'NET_CFG_NFS_MOUNT_OPTIONS': { 'mandatory': False,
+ 'default': 'nfsv4,minorversion=1' }
+ }
+ tags = list(net_cfg.keys())
+ config_inc = bld.path.find_node('config.inc')
+ try:
+ config_inc_lines = open(config_inc.abspath()).readlines()
+ except:
+ bld.fatal('network configuraiton \'%s\' read failed' %
+ (config_inc.abspath()))
+ for l in config_inc_lines:
+ if l.strip().startswith('NET_CFG_'):
+ ls = l.split('=', 1)
+ if len(ls) == 2:
+ lhs = ls[0].strip()
+ rhs = ls[1].strip()
+ if lhs in tags:
+ net_cfg[lhs]['default'] = rhs
try:
net_cfg_lines = open(bld.env.NET_CONFIG).readlines()
except:
bld.fatal('network configuraiton \'%s\' read failed' %
(bld.env.NET_CONFIG))
lc = 0
- sed = 'sed '
for l in net_cfg_lines:
lc += 1
if l.strip().startswith('NET_CFG_'):
- ls = l.split('=')
+ ls = l.split('=', 1)
if len(ls) != 2:
bld.fatal('network configuraiton \'%s\' ' + \
'parse error: %d: %s' % (bld.env.NET_CONFIG, lc, l))
lhs = ls[0].strip()
rhs = ls[1].strip()
- for tag in tags:
- if lhs == tag:
- transpose = [(':', '\:'), ('/', '\/')]
- trhs = ''
- for c in rhs:
- for t in transpose:
- if c == t[0]:
- trhs += t[1]
- c = None
- break
- if c is not None:
- trhs += c
- sed += "-e 's/@%s@/%s/' " % (tag, trhs)
+ if lhs in tags:
+ net_cfg[lhs]['value'] = rhs
+ for tag in net_cfg:
+ if 'value' not in net_cfg[tag]:
+ if net_cfg[tag]['mandatory']:
+ bld.fatal('network configuraiton \'%s\' ' + \
+ 'entry not found: %s' % (bld.env.NET_CONFIG, tag))
+ net_cfg[tag]['value'] = net_cfg[tag]['default']
+ updated = True
+ while updated:
+ updated = False
+ for tag in net_cfg:
+ for rtag in net_cfg:
+ if tag != rtag and 'value' in net_cfg[rtag]:
+ pattern = re.escape('@' + tag + '@')
+ repl = net_cfg[tag]['value']
+ value = re.sub(pattern, repl, net_cfg[rtag]['value'])
+ if value != net_cfg[rtag]['value']:
+ updated = True
+ net_cfg[rtag]['value'] = value
+ transpose = [(':', '\:'), ('/', '\/')]
+ sed = 'sed '
+ for tag in net_cfg:
+ tv = ''
+ for c in net_cfg[tag]['value']:
+ for t in transpose:
+ if c == t[0]:
+ tv += t[1]
+ c = None
+ break
+ if c is not None:
+ tv += c
+ sed += "-e 's/@%s@/%s/' " % (tag, tv)
bld(target="testsuite/include/rtems/bsd/test/network-config.h",
source="testsuite/include/rtems/bsd/test/network-config.h.in",
rule=sed + " < ${SRC} > ${TGT}",