Add the ability to spoof portmap, and put out a file that then
should get fed to pmap_set when starting the real portmapper.  This
allows for nfsroot with lockd enabled.

diff --git a/nfsmount/Makefile b/nfsmount/Makefile
index 1fa6091..bca293b 100644
--- a/nfsmount/Makefile
+++ b/nfsmount/Makefile
@@ -1,6 +1,6 @@
 include MCONFIG
 
-COMMON_OBJS = main.o mount.o portmap.o sunrpc.o
+COMMON_OBJS = main.o mount.o portmap.o dummypmap.o sunrpc.o
 PROG        = nfsmount
 LIB	    = libnfsmount.a
 LIBS        = $(KLIBC) $(LIBGCC)
@@ -11,6 +11,11 @@
 
 nfsmount: $(OBJS) $(CRT0) $(LIBS)
 	$(LD) $(LDFLAGS) -o $@ $(CRT0) $(OBJS) $(LIBS)
+	cp -f $@ $@.g
+	$(STRIP) $@
+
+dummypmap: dummypmap_test.o
+	$(LD) $(LDFLAGS) -o $@ $(CRT0) $^ $(LIBS)
 
 $(LIB): $(OBJS)
 	$(AR) cru $(LIB) $(OBJS)
diff --git a/nfsmount/dummypmap.c b/nfsmount/dummypmap.c
new file mode 100644
index 0000000..adf64c9
--- /dev/null
+++ b/nfsmount/dummypmap.c
@@ -0,0 +1,141 @@
+/*
+ * dummypmap.c
+ *
+ * Enough portmapper functionality that mount doesn't hang trying
+ * to start lockd.  Enables nfsroot with locking functionality.
+ *
+ * Note: the kernel will only speak to the local portmapper
+ * using RPC over UDP.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "sunrpc.h"
+
+struct portmap_call
+{
+        struct rpc_call rpc;
+        __u32 program;
+        __u32 version;
+        __u32 proto;
+        __u32 port;
+};
+
+struct portmap_reply
+{
+        struct rpc_reply rpc;
+        __u32 port;
+};
+
+FILE *portmap_file = 0;
+
+int dummy_portmap(void)
+{
+	int sock = socket(PF_INET, SOCK_DGRAM, 0);
+	struct sockaddr_in sin;
+	int pktlen, addrlen;
+	union {
+		struct portmap_call c;
+		unsigned char b[65536];	/* Max UDP packet size */
+	} pkt;
+	struct portmap_reply rply;
+	
+	if ( sock < 0 )
+		return -1;
+	
+	memset(&sin, 0, sizeof sin);
+	sin.sin_family      = AF_INET;
+	sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+	sin.sin_port        = htons(RPC_PMAP_PORT);
+	if ( bind(sock, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
+		int err = errno;
+		close(sock);
+		errno = err;
+		return -1;
+	}
+	
+	for(;;) {
+		addrlen = sizeof sin;
+		pktlen = recvfrom(sock, &pkt.c.rpc.hdr.udp, sizeof pkt, 0,
+				  (struct sockaddr *)&sin, &addrlen);
+		
+		if ( pktlen < 0 ) {
+			if ( errno == EINTR )
+				continue;
+			
+			return -1;
+		}
+		
+		/* +4 to skip the TCP fragment header */
+		if ( pktlen+4 < sizeof(struct portmap_call) )
+			continue;			/* Bad packet */
+		
+		if ( pkt.c.rpc.hdr.udp.msg_type != htonl(RPC_CALL) )
+			continue;			/* Bad packet */
+		
+		memset(&rply, 0, sizeof rply);
+		
+		rply.rpc.hdr.udp.xid      = pkt.c.rpc.hdr.udp.xid;
+		rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY);
+		
+		if ( pkt.c.rpc.rpc_vers != htonl(2) ) {
+			rply.rpc.reply_state = htonl(REPLY_DENIED);
+			/* state <- RPC_MISMATCH == 0 */
+		} else if ( pkt.c.rpc.program != htonl(PORTMAP_PROGRAM) ) {
+			rply.rpc.reply_state = htonl(PROG_UNAVAIL);
+		} else if ( pkt.c.rpc.prog_vers != htonl(2) ) {
+			rply.rpc.reply_state = htonl(PROG_MISMATCH);
+		} else if ( pkt.c.rpc.cred_len != 0 ||
+			    pkt.c.rpc.vrf_len != 0 ) {
+			/* Can't deal with credentials data; the kernel won't send them */
+			rply.rpc.reply_state = htonl(SYSTEM_ERR);
+		} else {
+			switch ( ntohl(pkt.c.rpc.proc) ) {
+			case PMAP_PROC_NULL:
+				break;
+			case PMAP_PROC_SET:
+				if ( pkt.c.proto == htonl(IPPROTO_TCP) ||
+				     pkt.c.proto == htonl(IPPROTO_UDP) ) {
+					if ( portmap_file )
+						fprintf(portmap_file, "%u %u %s %u\n",
+							ntohl(pkt.c.program), ntohl(pkt.c.version),
+							pkt.c.proto == htonl(IPPROTO_TCP) ? "tcp" : "udp",
+							ntohl(pkt.c.port));
+					rply.port = htonl(1);	/* TRUE = success */
+				}
+				break;
+			case PMAP_PROC_UNSET:
+				rply.port = htonl(1);	/* TRUE = success */
+				break;
+			case PMAP_PROC_GETPORT:
+				break;
+			case PMAP_PROC_DUMP:
+				break;
+			default:
+				rply.rpc.reply_state = htonl(PROC_UNAVAIL);
+				break;
+			}
+		}
+		
+		sendto(sock, &rply.rpc.hdr.udp, sizeof rply - 4, 0,
+		       (struct sockaddr *)&sin, addrlen);
+	}
+}
+      
+#ifdef TEST
+int main(int argc, char *argv[])
+{
+  if ( argc > 1 )
+    portmap_file = fopen(argv[1], "a");
+
+  return dummy_portmap();
+}
+#endif
+
diff --git a/nfsmount/dummypmap.h b/nfsmount/dummypmap.h
new file mode 100644
index 0000000..2625133
--- /dev/null
+++ b/nfsmount/dummypmap.h
@@ -0,0 +1,11 @@
+/*
+ * dummyportmap.h
+ *
+ * Functions for the portmap spoofer
+ */
+
+#include <stdio.h>
+
+extern FILE *portmap_file;
+int dummy_portmap(void);
+
diff --git a/nfsmount/dummypmap_test.c b/nfsmount/dummypmap_test.c
new file mode 100644
index 0000000..d81a141
--- /dev/null
+++ b/nfsmount/dummypmap_test.c
@@ -0,0 +1,2 @@
+#define TEST
+#include "dummypmap.c"
diff --git a/nfsmount/main.c b/nfsmount/main.c
index 361a545..c5eae47 100644
--- a/nfsmount/main.c
+++ b/nfsmount/main.c
@@ -10,11 +10,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
 
 #include <linux/nfs_mount.h>
 
 #include "nfsmount.h"
 #include "sunrpc.h"
+#include "dummypmap.h"
 
 static char *progname;
 
@@ -161,17 +163,22 @@
 	char *hostname;
 	char *path;
 	int c;
+	int spoof_portmap = 0;
 
 	progname = argv[0];
 
 	gettimeofday(&now, NULL);
 	srand48(now.tv_usec ^ (now.tv_sec << 24));
 
-	while ((c = getopt(argc, argv, "o:")) != EOF) {
+	while ((c = getopt(argc, argv, "o:p:")) != EOF) {
 		switch (c) {
 		case 'o':
 			parse_opts(optarg);
 			break;
+		case 'p':
+			spoof_portmap = 1;
+			portmap_file  = fopen(optarg, "w");
+			break;
 		case '?':
 			fprintf(stderr, "%s: invalid option -%c\n",
 				progname, optopt);
@@ -213,10 +220,26 @@
 
 	check_path(path);
 
+	if ( spoof_portmap ) {
+		spoof_portmap = fork();
+		if ( spoof_portmap == -1 ) {
+			fprintf(stderr, "%s: cannot fork\n", progname);
+			exit(1);
+		} else if ( spoof_portmap == 0 ) {
+			/* Child process */
+			dummy_portmap();
+			_exit(255); /* Error */
+		}
+	}
+
 	if (nfs_mount(rem_name, hostname, server, rem_path, path,
 		      &mount_data) != 0)
 		return 1;
 
+	/* If we set up the spoofer, tear it down now */
+	if ( spoof_portmap )
+		kill(SIGTERM, spoof_portmap);
+
 	free(rem_name);
 
 	return 0;
diff --git a/nfsmount/sunrpc.h b/nfsmount/sunrpc.h
index 7706eea..563e039 100644
--- a/nfsmount/sunrpc.h
+++ b/nfsmount/sunrpc.h
@@ -9,16 +9,29 @@
 #define RPC_REPLY	1
 
 #define PORTMAP_PROGRAM	100000
+#define NLM_PROGRAM	100021
 
 #define RPC_PMAP_PROGRAM	100000
 #define RPC_PMAP_VERSION	2
 #define RPC_PMAP_PORT		111
 
+#define PMAP_PROC_NULL		0
+#define PMAP_PROC_SET		1
+#define PMAP_PROC_UNSET		2
 #define PMAP_PROC_GETPORT	3
+#define PMAP_PROC_DUMP		4
 
 #define LAST_FRAG	0x80000000
 
 #define REPLY_OK	0
+#define REPLY_DENIED    1
+
+#define SUCCESS		0
+#define PROG_UNAVAIL	1
+#define PROG_MISMATCH	2
+#define PROC_UNAVAIL	3
+#define GARBAGE_ARGS	4
+#define SYSTEM_ERR	5
 
 struct rpc_udp_header
 {