summaryrefslogtreecommitdiffstats
path: root/usr/kinit/nfsmount/portmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/kinit/nfsmount/portmap.c')
-rw-r--r--usr/kinit/nfsmount/portmap.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/usr/kinit/nfsmount/portmap.c b/usr/kinit/nfsmount/portmap.c
new file mode 100644
index 0000000..0a3e2d0
--- /dev/null
+++ b/usr/kinit/nfsmount/portmap.c
@@ -0,0 +1,73 @@
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h> /* __constant_hton* */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+struct portmap_call {
+ struct rpc_call rpc;
+ uint32_t program;
+ uint32_t version;
+ uint32_t proto;
+ uint32_t port;
+};
+
+struct portmap_reply {
+ struct rpc_reply rpc;
+ uint32_t port;
+};
+
+static struct portmap_call call = {
+ .rpc = {
+ .program = __constant_htonl(RPC_PMAP_PROGRAM),
+ .prog_vers = __constant_htonl(RPC_PMAP_VERSION),
+ .proc = __constant_htonl(PMAP_PROC_GETPORT),
+ }
+};
+
+uint32_t portmap(uint32_t server, uint32_t program, uint32_t version, uint32_t proto)
+{
+ struct portmap_reply reply;
+ struct client *clnt;
+ struct rpc rpc;
+ uint32_t port = 0;
+
+ clnt = tcp_client(server, RPC_PMAP_PORT, 0);
+ if (clnt == NULL) {
+ clnt = udp_client(server, RPC_PMAP_PORT, 0);
+ if (clnt == NULL)
+ goto bail;
+ }
+
+ call.program = htonl(program);
+ call.version = htonl(version);
+ call.proto = htonl(proto);
+
+ rpc.call = (struct rpc_call *)&call;
+ rpc.call_len = sizeof(call);
+ rpc.reply = (struct rpc_reply *)&reply;
+ rpc.reply_len = sizeof(reply);
+
+ if (rpc_call(clnt, &rpc) < 0)
+ goto bail;
+
+ if (rpc.reply_len < sizeof(reply)) {
+ fprintf(stderr, "incomplete reply: %zu < %zu\n",
+ rpc.reply_len, sizeof(reply));
+ goto bail;
+ }
+
+ port = ntohl(reply.port);
+
+bail:
+ dprintf("Port for %d/%d[%s]: %d\n", program, version,
+ proto == IPPROTO_TCP ? "tcp" : "udp", port);
+
+ if (clnt)
+ client_free(clnt);
+
+ return port;
+}