aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@gmail.com>2010-01-30 09:48:21 +0000
committerMarty Connor <mdc@etherboot.org>2010-01-31 19:21:00 -0500
commit1548189ffa8a54275ed58476993dba6dcaf799a0 (patch)
treede749661196bde3e5bdcdf77f1636b1ceaff46d5
parente501e6e19e819652c5fdd1b69a5d4921d00106bd (diff)
downloadipxe-1548189ffa8a54275ed58476993dba6dcaf799a0.zip
ipxe-1548189ffa8a54275ed58476993dba6dcaf799a0.tar.gz
ipxe-1548189ffa8a54275ed58476993dba6dcaf799a0.tar.bz2
[proto] Remove unsupported NFS protocol
The NFS protocol code came from legacy Etherboot and was never updated to work as a gPXE protocol. There has been no demand for this protocol, so this patch removes it. I have an unfinished NFSv3 over TCP implementation for gPXE that can be used as the base for new work, should we want to resurrect this protocol. Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com> Signed-off-by: Marty Connor <mdc@etherboot.org>
-rw-r--r--src/config/config.c3
-rw-r--r--src/config/general.h1
-rw-r--r--src/core/main.c1
-rw-r--r--src/core/settings.c2
-rw-r--r--src/include/nfs.h63
-rw-r--r--src/proto/nfs.c616
6 files changed, 1 insertions, 685 deletions
diff --git a/src/config/config.c b/src/config/config.c
index 8252402..dd3b09a 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -109,9 +109,6 @@ REQUIRE_OBJECT ( pxe_call );
#ifdef DOWNLOAD_PROTO_TFTP
REQUIRE_OBJECT ( tftp );
#endif
-#ifdef DOWNLOAD_PROTO_NFS
-REQUIRE_OBJECT ( nfs );
-#endif
#ifdef DOWNLOAD_PROTO_HTTP
REQUIRE_OBJECT ( http );
#endif
diff --git a/src/config/general.h b/src/config/general.h
index eb8a0b5..3501846 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -54,7 +54,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
-#undef DOWNLOAD_PROTO_NFS /* Network File System */
#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
diff --git a/src/core/main.c b/src/core/main.c
index 74452b7..ec052b0 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -9,7 +9,6 @@ Literature dealing with the network protocols:
DHCP - RFC2131, RFC2132 (options)
TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
- NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
IGMP - RFC1112
**************************************************************************/
diff --git a/src/core/settings.c b/src/core/settings.c
index 2fefdb9..7d83101 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -1426,7 +1426,7 @@ struct setting filename_setting __setting = {
/** Root path setting */
struct setting root_path_setting __setting = {
.name = "root-path",
- .description = "NFS/iSCSI root path",
+ .description = "iSCSI root path",
.tag = DHCP_ROOT_PATH,
.type = &setting_type_string,
};
diff --git a/src/include/nfs.h b/src/include/nfs.h
deleted file mode 100644
index 0877bb6..0000000
--- a/src/include/nfs.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _NFS_H
-#define _NFS_H
-
-#define SUNRPC_PORT 111
-
-#define PROG_PORTMAP 100000
-#define PROG_NFS 100003
-#define PROG_MOUNT 100005
-
-#define MSG_CALL 0
-#define MSG_REPLY 1
-
-#define PORTMAP_GETPORT 3
-
-#define MOUNT_ADDENTRY 1
-#define MOUNT_UMOUNTALL 4
-
-#define NFS_LOOKUP 4
-#define NFS_READLINK 5
-#define NFS_READ 6
-
-#define NFS_FHSIZE 32
-
-#define NFSERR_PERM 1
-#define NFSERR_NOENT 2
-#define NFSERR_ACCES 13
-#define NFSERR_ISDIR 21
-#define NFSERR_INVAL 22
-
-/* Block size used for NFS read accesses. A RPC reply packet (including all
- * headers) must fit within a single Ethernet frame to avoid fragmentation.
- * Chosen to be a power of two, as most NFS servers are optimized for this. */
-#define NFS_READ_SIZE 1024
-
-#define NFS_MAXLINKDEPTH 16
-
-struct rpc_t {
- struct iphdr ip;
- struct udphdr udp;
- union {
- uint8_t data[300]; /* longest RPC call must fit!!!! */
- struct {
- uint32_t id;
- uint32_t type;
- uint32_t rpcvers;
- uint32_t prog;
- uint32_t vers;
- uint32_t proc;
- uint32_t data[1];
- } call;
- struct {
- uint32_t id;
- uint32_t type;
- uint32_t rstatus;
- uint32_t verifier;
- uint32_t v2;
- uint32_t astatus;
- uint32_t data[1];
- } reply;
- } u;
-} PACKED;
-
-#endif /* _NFS_H */
diff --git a/src/proto/nfs.c b/src/proto/nfs.c
deleted file mode 100644
index 943081a..0000000
--- a/src/proto/nfs.c
+++ /dev/null
@@ -1,616 +0,0 @@
-#if 0
-
-#include <gpxe/init.h>
-#include <gpxe/in.h>
-
-/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read:
- * large portions are copied verbatim) as distributed in OSKit 0.97. A few
- * changes were necessary to adapt the code to Etherboot and to fix several
- * inconsistencies. Also the RPC message preparation is done "by hand" to
- * avoid adding netsprintf() which I find hard to understand and use. */
-
-/* NOTE 2: Etherboot does not care about things beyond the kernel image, so
- * it loads the kernel image off the boot server (ARP_SERVER) and does not
- * access the client root disk (root-path in dhcpd.conf), which would use
- * ARP_ROOTSERVER. The root disk is something the operating system we are
- * about to load needs to use. This is different from the OSKit 0.97 logic. */
-
-/* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14
- * If a symlink is encountered, it is followed as far as possible (recursion
- * possible, maximum 16 steps). There is no clearing of ".."'s inside the
- * path, so please DON'T DO THAT. thx. */
-
-#define START_OPORT 700 /* mountd usually insists on secure ports */
-#define OPORT_SWEEP 200 /* make sure we don't leave secure range */
-
-static int oport = START_OPORT;
-static struct sockaddr_in mount_server;
-static struct sockaddr_in nfs_server;
-static unsigned long rpc_id;
-
-/**************************************************************************
-RPC_INIT - set up the ID counter to something fairly random
-**************************************************************************/
-void rpc_init(void)
-{
- unsigned long t;
-
- t = currticks();
- rpc_id = t ^ (t << 8) ^ (t << 16);
-}
-
-/**************************************************************************
-RPC_PRINTERROR - Print a low level RPC error message
-**************************************************************************/
-static void rpc_printerror(struct rpc_t *rpc)
-{
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus) {
- /* rpc_printerror() is called for any RPC related error,
- * suppress output if no low level RPC error happened. */
- DBG("RPC error: (%ld,%ld,%ld)\n", ntohl(rpc->u.reply.rstatus),
- ntohl(rpc->u.reply.verifier),
- ntohl(rpc->u.reply.astatus));
- }
-}
-
-/**************************************************************************
-AWAIT_RPC - Wait for an rpc packet
-**************************************************************************/
-static int await_rpc(int ival, void *ptr,
- unsigned short ptype __unused, struct iphdr *ip,
- struct udphdr *udp, struct tcphdr *tcp __unused)
-{
- struct rpc_t *rpc;
- if (!udp)
- return 0;
- if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
- return 0;
- if (ntohs(udp->dest) != ival)
- return 0;
- if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) + 8)
- return 0;
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (*(unsigned long *)ptr != ntohl(rpc->u.reply.id))
- return 0;
- if (MSG_REPLY != ntohl(rpc->u.reply.type))
- return 0;
- return 1;
-}
-
-/**************************************************************************
-RPC_LOOKUP - Lookup RPC Port numbers
-**************************************************************************/
-static int rpc_lookup(struct sockaddr_in *addr, int prog, int ver, int sport)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- int retries;
- long *p;
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_PORTMAP);
- buf.u.call.vers = htonl(2); /* portmapper is version 2 */
- buf.u.call.proc = htonl(PORTMAP_GETPORT);
- p = (long *)buf.u.call.data;
- *p++ = 0; *p++ = 0; /* auth credential */
- *p++ = 0; *p++ = 0; /* auth verifier */
- *p++ = htonl(prog);
- *p++ = htonl(ver);
- *p++ = htonl(IP_UDP);
- *p++ = 0;
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout;
- udp_transmit(addr->sin_addr.s_addr, sport, addr->sin_port,
- (char *)p - (char *)&buf, &buf);
- timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- if (await_reply(await_rpc, sport, &id, timeout)) {
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus) {
- rpc_printerror(rpc);
- return 0;
- } else {
- return ntohl(rpc->u.reply.data[0]);
- }
- }
- }
- return 0;
-}
-
-/**************************************************************************
-RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries
-**************************************************************************/
-static long *rpc_add_credentials(long *p)
-{
- int hl;
-
- /* Here's the executive summary on authentication requirements of the
- * various NFS server implementations: Linux accepts both AUTH_NONE
- * and AUTH_UNIX authentication (also accepts an empty hostname field
- * in the AUTH_UNIX scheme). *BSD refuses AUTH_NONE, but accepts
- * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
- * scheme). To be safe, use AUTH_UNIX and pass the hostname if we have
- * it (if the BOOTP/DHCP reply didn't give one, just use an empty
- * hostname). */
-
- hl = (hostnamelen + 3) & ~3;
-
- /* Provide an AUTH_UNIX credential. */
- *p++ = htonl(1); /* AUTH_UNIX */
- *p++ = htonl(hl+20); /* auth length */
- *p++ = htonl(0); /* stamp */
- *p++ = htonl(hostnamelen); /* hostname string */
- if (hostnamelen & 3) {
- *(p + hostnamelen / 4) = 0; /* add zero padding */
- }
- memcpy(p, hostname, hostnamelen);
- p += hl / 4;
- *p++ = 0; /* uid */
- *p++ = 0; /* gid */
- *p++ = 0; /* auxiliary gid list */
-
- /* Provide an AUTH_NONE verifier. */
- *p++ = 0; /* AUTH_NONE */
- *p++ = 0; /* auth length */
-
- return p;
-}
-
-/**************************************************************************
-NFS_PRINTERROR - Print a NFS error message
-**************************************************************************/
-static void nfs_printerror(int err)
-{
- switch (-err) {
- case NFSERR_PERM:
- printf("Not owner\n");
- break;
- case NFSERR_NOENT:
- printf("No such file or directory\n");
- break;
- case NFSERR_ACCES:
- printf("Permission denied\n");
- break;
- case NFSERR_ISDIR:
- printf("Directory given where filename expected\n");
- break;
- case NFSERR_INVAL:
- printf("Invalid filehandle\n");
- break; // INVAL is not defined in NFSv2, some NFS-servers
- // seem to use it in answers to v2 nevertheless.
- case 9998:
- printf("low-level RPC failure (parameter decoding problem?)\n");
- break;
- case 9999:
- printf("low-level RPC failure (authentication problem?)\n");
- break;
- default:
- printf("Unknown NFS error %d\n", -err);
- }
-}
-
-/**************************************************************************
-NFS_MOUNT - Mount an NFS Filesystem
-**************************************************************************/
-static int nfs_mount(struct sockaddr_in *server, char *path, char *fh, int sport)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- int retries;
- long *p;
- int pathlen = strlen(path);
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_MOUNT);
- buf.u.call.vers = htonl(1); /* mountd is version 1 */
- buf.u.call.proc = htonl(MOUNT_ADDENTRY);
- p = rpc_add_credentials((long *)buf.u.call.data);
- *p++ = htonl(pathlen);
- if (pathlen & 3) {
- *(p + pathlen / 4) = 0; /* add zero padding */
- }
- memcpy(p, path, pathlen);
- p += (pathlen + 3) / 4;
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout;
- udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
- (char *)p - (char *)&buf, &buf);
- timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- if (await_reply(await_rpc, sport, &id, timeout)) {
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus || rpc->u.reply.data[0]) {
- rpc_printerror(rpc);
- if (rpc->u.reply.rstatus) {
- /* RPC failed, no verifier, data[0] */
- return -9999;
- }
- if (rpc->u.reply.astatus) {
- /* RPC couldn't decode parameters */
- return -9998;
- }
- return -ntohl(rpc->u.reply.data[0]);
- } else {
- memcpy(fh, rpc->u.reply.data + 1, NFS_FHSIZE);
- return 0;
- }
- }
- }
- return -1;
-}
-
-/**************************************************************************
-NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
-**************************************************************************/
-static void nfs_umountall(struct sockaddr_in *server)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- int retries;
- long *p;
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_MOUNT);
- buf.u.call.vers = htonl(1); /* mountd is version 1 */
- buf.u.call.proc = htonl(MOUNT_UMOUNTALL);
- p = rpc_add_credentials((long *)buf.u.call.data);
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- udp_transmit(server->sin_addr.s_addr, oport, server->sin_port,
- (char *)p - (char *)&buf, &buf);
- if (await_reply(await_rpc, oport, &id, timeout)) {
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus) {
- rpc_printerror(rpc);
- }
- break;
- }
- }
-}
-
-/**************************************************************************
-NFS_RESET - Reset the NFS subsystem
-**************************************************************************/
-static void nfs_reset ( void ) {
- /* If we have a mount server, call nfs_umountall() */
- if ( mount_server.sin_addr.s_addr ) {
- nfs_umountall ( &mount_server );
- }
- /* Zero the data structures */
- memset ( &mount_server, 0, sizeof ( mount_server ) );
- memset ( &nfs_server, 0, sizeof ( nfs_server ) );
-}
-
-/***************************************************************************
- * NFS_READLINK (AH 2003-07-14)
- * This procedure is called when read of the first block fails -
- * this probably happens when it's a directory or a symlink
- * In case of successful readlink(), the dirname is manipulated,
- * so that inside the nfs() function a recursion can be done.
- **************************************************************************/
-static int nfs_readlink(struct sockaddr_in *server, char *fh __unused,
- char *path, char *nfh, int sport)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- long *p;
- int retries;
- int pathlen = strlen(path);
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_NFS);
- buf.u.call.vers = htonl(2); /* nfsd is version 2 */
- buf.u.call.proc = htonl(NFS_READLINK);
- p = rpc_add_credentials((long *)buf.u.call.data);
- memcpy(p, nfh, NFS_FHSIZE);
- p += (NFS_FHSIZE / 4);
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
- (char *)p - (char *)&buf, &buf);
- if (await_reply(await_rpc, sport, &id, timeout)) {
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus || rpc->u.reply.data[0]) {
- rpc_printerror(rpc);
- if (rpc->u.reply.rstatus) {
- /* RPC failed, no verifier, data[0] */
- return -9999;
- }
- if (rpc->u.reply.astatus) {
- /* RPC couldn't decode parameters */
- return -9998;
- }
- return -ntohl(rpc->u.reply.data[0]);
- } else {
- // It *is* a link.
- // If it's a relative link, append everything to dirname, filename TOO!
- retries = strlen ( (char *)(&(rpc->u.reply.data[2]) ));
- if ( *((char *)(&(rpc->u.reply.data[2]))) != '/' ) {
- path[pathlen++] = '/';
- while ( ( retries + pathlen ) > 298 ) {
- retries--;
- }
- if ( retries > 0 ) {
- memcpy(path + pathlen, &(rpc->u.reply.data[2]), retries + 1);
- } else { retries = 0; }
- path[pathlen + retries] = 0;
- } else {
- // Else make it the only path.
- if ( retries > 298 ) { retries = 298; }
- memcpy ( path, &(rpc->u.reply.data[2]), retries + 1 );
- path[retries] = 0;
- }
- return 0;
- }
- }
- }
- return -1;
-}
-/**************************************************************************
-NFS_LOOKUP - Lookup Pathname
-**************************************************************************/
-static int nfs_lookup(struct sockaddr_in *server, char *fh, char *path, char *nfh,
- int sport)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- long *p;
- int retries;
- int pathlen = strlen(path);
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_NFS);
- buf.u.call.vers = htonl(2); /* nfsd is version 2 */
- buf.u.call.proc = htonl(NFS_LOOKUP);
- p = rpc_add_credentials((long *)buf.u.call.data);
- memcpy(p, fh, NFS_FHSIZE);
- p += (NFS_FHSIZE / 4);
- *p++ = htonl(pathlen);
- if (pathlen & 3) {
- *(p + pathlen / 4) = 0; /* add zero padding */
- }
- memcpy(p, path, pathlen);
- p += (pathlen + 3) / 4;
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
- (char *)p - (char *)&buf, &buf);
- if (await_reply(await_rpc, sport, &id, timeout)) {
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus || rpc->u.reply.data[0]) {
- rpc_printerror(rpc);
- if (rpc->u.reply.rstatus) {
- /* RPC failed, no verifier, data[0] */
- return -9999;
- }
- if (rpc->u.reply.astatus) {
- /* RPC couldn't decode parameters */
- return -9998;
- }
- return -ntohl(rpc->u.reply.data[0]);
- } else {
- memcpy(nfh, rpc->u.reply.data + 1, NFS_FHSIZE);
- return 0;
- }
- }
- }
- return -1;
-}
-
-/**************************************************************************
-NFS_READ - Read File on NFS Server
-**************************************************************************/
-static int nfs_read(struct sockaddr_in *server, char *fh, int offset, int len,
- int sport)
-{
- struct rpc_t buf, *rpc;
- unsigned long id;
- int retries;
- long *p;
-
- static int tokens=0;
- /*
- * Try to implement something similar to a window protocol in
- * terms of response to losses. On successful receive, increment
- * the number of tokens by 1 (cap at 256). On failure, halve it.
- * When the number of tokens is >= 2, use a very short timeout.
- */
-
- id = rpc_id++;
- buf.u.call.id = htonl(id);
- buf.u.call.type = htonl(MSG_CALL);
- buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */
- buf.u.call.prog = htonl(PROG_NFS);
- buf.u.call.vers = htonl(2); /* nfsd is version 2 */
- buf.u.call.proc = htonl(NFS_READ);
- p = rpc_add_credentials((long *)buf.u.call.data);
- memcpy(p, fh, NFS_FHSIZE);
- p += NFS_FHSIZE / 4;
- *p++ = htonl(offset);
- *p++ = htonl(len);
- *p++ = 0; /* unused parameter */
- for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
- long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
- if (tokens >= 2)
- timeout = TICKS_PER_SEC/2;
-
- udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
- (char *)p - (char *)&buf, &buf);
- if (await_reply(await_rpc, sport, &id, timeout)) {
- if (tokens < 256)
- tokens++;
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
- if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
- rpc->u.reply.astatus || rpc->u.reply.data[0]) {
- rpc_printerror(rpc);
- if (rpc->u.reply.rstatus) {
- /* RPC failed, no verifier, data[0] */
- return -9999;
- }
- if (rpc->u.reply.astatus) {
- /* RPC couldn't decode parameters */
- return -9998;
- }
- return -ntohl(rpc->u.reply.data[0]);
- } else {
- return 0;
- }
- } else
- tokens >>= 1;
- }
- return -1;
-}
-
-/**************************************************************************
-NFS - Download extended BOOTP data, or kernel image from NFS server
-**************************************************************************/
-static int nfs ( char *url __unused, struct sockaddr_in *server,
- char *name, struct buffer *buffer ) {
- static int recursion = 0;
- int sport;
- int err, namelen = strlen(name);
- char dirname[300], *fname;
- char dirfh[NFS_FHSIZE]; /* file handle of directory */
- char filefh[NFS_FHSIZE]; /* file handle of kernel image */
- int rlen, size, offs, len;
- struct rpc_t *rpc;
-
- sport = oport++;
- if (oport > START_OPORT+OPORT_SWEEP) {
- oport = START_OPORT;
- }
-
- mount_server.sin_addr = nfs_server.sin_addr = server->sin_addr;
- mount_server.sin_port = rpc_lookup(server, PROG_MOUNT, 1, sport);
- if ( ! mount_server.sin_port ) {
- DBG ( "Cannot get mount port from %s:%d\n",
- inet_ntoa ( server->sin_addr ), server->sin_port );
- return 0;
- }
- nfs_server.sin_port = rpc_lookup(server, PROG_NFS, 2, sport);
- if ( ! mount_server.sin_port ) {
- DBG ( "Cannot get nfs port from %s:%d\n",
- inet_ntoa ( server->sin_addr ), server->sin_port );
- return 0;
- }
-
- if ( name != dirname ) {
- memcpy(dirname, name, namelen + 1);
- }
- recursion = 0;
-nfssymlink:
- if ( recursion > NFS_MAXLINKDEPTH ) {
- DBG ( "\nRecursion: More than %d symlinks followed. Abort.\n",
- NFS_MAXLINKDEPTH );
- return 0;
- }
- recursion++;
- fname = dirname + (namelen - 1);
- while (fname >= dirname) {
- if (*fname == '/') {
- *fname = '\0';
- fname++;
- break;
- }
- fname--;
- }
- if (fname < dirname) {
- DBG("can't parse file name %s\n", name);
- return 0;
- }
-
- err = nfs_mount(&mount_server, dirname, dirfh, sport);
- if (err) {
- DBG("mounting %s: ", dirname);
- nfs_printerror(err);
- /* just to be sure... */
- nfs_reset();
- return 0;
- }
-
- err = nfs_lookup(&nfs_server, dirfh, fname, filefh, sport);
- if (err) {
- DBG("looking up %s: ", fname);
- nfs_printerror(err);
- nfs_reset();
- return 0;
- }
-
- offs = 0;
- size = -1; /* will be set properly with the first reply */
- len = NFS_READ_SIZE; /* first request is always full size */
- do {
- err = nfs_read(&nfs_server, filefh, offs, len, sport);
- if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) {
- // An error occured. NFS servers tend to sending
- // errors 21 / 22 when symlink instead of real file
- // is requested. So check if it's a symlink!
- if ( nfs_readlink(&nfs_server, dirfh, dirname,
- filefh, sport) == 0 ) {
- printf("\nLoading symlink:%s ..",dirname);
- goto nfssymlink;
- }
- nfs_printerror(err);
- nfs_reset();
- return 0;
- }
- if (err) {
- printf("\nError reading at offset %d: ", offs);
- nfs_printerror(err);
- nfs_reset();
- return 0;
- }
-
- rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-
- /* size must be found out early to allow EOF detection */
- if (size == -1) {
- size = ntohl(rpc->u.reply.data[6]);
- }
- rlen = ntohl(rpc->u.reply.data[18]);
- if (rlen > len) {
- rlen = len; /* shouldn't happen... */
- }
-
- if ( ! fill_buffer ( buffer, &rpc->u.reply.data[19],
- offs, rlen ) ) {
- nfs_reset();
- return 0;
- }
-
- offs += rlen;
- /* last request is done with matching requested read size */
- if (size-offs < NFS_READ_SIZE) {
- len = size-offs;
- }
- } while (len != 0);
- /* len == 0 means that all the file has been read */
- return 1;
-}
-
-struct protocol nfs_protocol __protocol = {
- .name = "nfs",
- .default_port = SUNRPC_PORT,
- .load = nfs,
-};
-
-#endif