diff options
Diffstat (limited to 'usr/kinit/nfsmount/portmap.c')
-rw-r--r-- | usr/kinit/nfsmount/portmap.c | 73 |
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; +} |