summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/mount/network.c79
-rw-r--r--utils/mount/network.h3
-rw-r--r--utils/mount/nfs4mount.c1
3 files changed, 83 insertions, 0 deletions
diff --git a/utils/mount/network.c b/utils/mount/network.c
index c092571..a5b0b71 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -53,6 +53,10 @@
#define NFS_PORT 2049
#endif
+#if SIZEOF_SOCKLEN_T - 0 == 0
+#define socklen_t unsigned int
+#endif
+
extern int nfs_mount_data_version;
extern char *progname;
extern int verbose;
@@ -510,3 +514,78 @@ void mnt_closeclnt(CLIENT *clnt, int msock)
clnt_destroy(clnt);
close(msock);
}
+
+/*
+ * Sigh... getport() doesn't actually check the version number.
+ * In order to make sure that the server actually supports the service
+ * we're requesting, we open and RPC client, and fire off a NULL
+ * RPC call.
+ */
+int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
+ const unsigned long vers, const unsigned int prot,
+ struct sockaddr_in *caddr)
+{
+ CLIENT *clnt = NULL;
+ int sock, stat;
+ static char clnt_res;
+ struct sockaddr dissolve;
+
+ rpc_createerr.cf_stat = stat = errno = 0;
+ sock = get_socket(saddr, prot, FALSE, TRUE);
+ if (sock == RPC_ANYSOCK) {
+ if (errno == ETIMEDOUT) {
+ /*
+ * TCP timeout. Bubble up the error to see
+ * how it should be handled.
+ */
+ rpc_createerr.cf_stat = RPC_TIMEDOUT;
+ }
+ return 0;
+ }
+
+ if (caddr) {
+ /* Get the address of our end of this connection */
+ socklen_t len = sizeof(*caddr);
+ if (getsockname(sock, caddr, &len) != 0)
+ caddr->sin_family = 0;
+ }
+
+ switch(prot) {
+ case IPPROTO_UDP:
+ /* The socket is connected (so we could getsockname successfully),
+ * but some servers on multi-homed hosts reply from
+ * the wrong address, so if we stay connected, we lose the reply.
+ */
+ dissolve.sa_family = AF_UNSPEC;
+ connect(sock, &dissolve, sizeof(dissolve));
+
+ clnt = clntudp_bufcreate(saddr, prog, vers,
+ RETRY_TIMEOUT, &sock,
+ RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ break;
+ case IPPROTO_TCP:
+ clnt = clnttcp_create(saddr, prog, vers, &sock,
+ RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ break;
+ }
+ if (!clnt) {
+ close(sock);
+ return 0;
+ }
+ memset(&clnt_res, 0, sizeof(clnt_res));
+ stat = clnt_call(clnt, NULLPROC,
+ (xdrproc_t)xdr_void, (caddr_t)NULL,
+ (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
+ TIMEOUT);
+ if (stat) {
+ clnt_geterr(clnt, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = stat;
+ }
+ clnt_destroy(clnt);
+ close(sock);
+
+ if (stat == RPC_SUCCESS)
+ return 1;
+ else
+ return 0;
+}
diff --git a/utils/mount/network.h b/utils/mount/network.h
index b3a5525..0f24a32 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -30,6 +30,9 @@
int probe_bothports(clnt_addr_t *, clnt_addr_t *);
int nfs_gethostbyname(const char *, struct sockaddr_in *);
int nfs_call_umount(clnt_addr_t *, dirpath *);
+int clnt_ping(struct sockaddr_in *, const unsigned long,
+ const unsigned long, const unsigned int,
+ struct sockaddr_in *);
int start_statd(void);
diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
index 26a6896..52b0261 100644
--- a/utils/mount/nfs4mount.c
+++ b/utils/mount/nfs4mount.c
@@ -46,6 +46,7 @@
#include "nfs4_mount.h"
#include "nfs_mount.h"
#include "error.h"
+#include "network.h"
#if defined(VAR_LOCK_DIR)
#define DEFAULT_DIR VAR_LOCK_DIR