From 7e282d25068ec09163e00cbe5819a1b5be3571be Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 31 Aug 2021 18:46:37 +1000 Subject: 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 --- buildset/default.ini | 2 +- config.inc | 7 +- freebsd/lib/libc/rpc/auth_unix.c | 7 + freebsd/lib/libc/rpc/clnt_dg.c | 17 +- freebsd/lib/libc/rpc/clnt_generic.c | 5 + freebsd/lib/libc/rpc/clnt_vc.c | 18 + freebsd/lib/libc/rpc/getnetconfig.c | 40 +- freebsd/lib/libc/rpc/rpc_generic.c | 2 + freebsd/lib/libc/rpc/rpcb_clnt.c | 4 + rtemsbsd/fs/nfsclient/nfs.c | 926 ++++++++++++++++++++++++++++++++---- rtemsbsd/rtems/rtems-kernel-vfs.c | 2 +- testsuite/nfs01/test_main.c | 5 +- waf_libbsd.py | 80 +++- 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 #include +#include + +#include +#include +#include + +#include +#include + #include #include #include #include + #include 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 : 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}", -- cgit v1.2.3