diff options
author | Amit Gud <agud@redhat.com> | 2006-06-12 19:08:27 -0400 |
---|---|---|
committer | Neil Brown <neilb@suse.de> | 2006-06-16 12:19:45 +1000 |
commit | 4e2bae795e5eaf9922f0b966ab5df64994c836a2 (patch) | |
tree | 5bd9031586cbc3f6e644d9967d54acf00a7ebb4d /support/nfs/conn.c | |
parent | a0520fa1a41bd33815b331b660b4545f2723495c (diff) | |
download | nfs-utils-4e2bae795e5eaf9922f0b966ab5df64994c836a2.tar.gz nfs-utils-4e2bae795e5eaf9922f0b966ab5df64994c836a2.tar.xz nfs-utils-4e2bae795e5eaf9922f0b966ab5df64994c836a2.zip |
Move NFS mount code from util-linux to nfs-utils - part 2
Adds the support functions needed for mount and umount. This
functionality will someday be available in the form of shared mount
library.
Signed-off-by: Amit Gud <agud@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'support/nfs/conn.c')
-rw-r--r-- | support/nfs/conn.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/support/nfs/conn.c b/support/nfs/conn.c new file mode 100644 index 0000000..a020394 --- /dev/null +++ b/support/nfs/conn.c @@ -0,0 +1,211 @@ +/* + * conn.c -- NFS client mount / umount connection code support functions + * + * 2006-06-06 Amit Gud <agud@redhat.com> + * - Moved code snippets to nfs-utils/support/nfs from util-linux/mount/nfsmount.c + * + */ + +#include <errno.h> +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "conn.h" + +extern int verbose; + +/* Map an NFS version into the corresponding Mountd version */ +u_long nfsvers_to_mnt(const u_long vers) +{ + static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 }; + if (vers <= 3) + return nfs_to_mnt[vers]; + return 0; +} + +/* Map a Mountd version into the corresponding NFS version */ +u_long mntvers_to_nfs(const u_long vers) +{ + static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 }; + if (vers <= 3) + return mnt_to_nfs[vers]; + return 0; +} + +/* + * Create a socket that is locally bound to a + * reserve or non-reserve port. For any failures, + * RPC_ANYSOCK is returned which will cause + * the RPC code to create the socket instead. + */ +int get_socket(struct sockaddr_in *saddr, u_int p_prot, int resvp) +{ + int so, cc, type; + struct sockaddr_in laddr; + socklen_t namelen = sizeof(laddr); + + type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM); + if ((so = socket (AF_INET, type, p_prot)) < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (verbose) { + fprintf(stderr, + "mount: Unable to create %s socket: errno %d (%s)\n", + p_prot == IPPROTO_UDP ? "UDP" : "TCP", + errno, strerror(errno)); + } + return RPC_ANYSOCK; + } + laddr.sin_family = AF_INET; + laddr.sin_port = 0; + laddr.sin_addr.s_addr = htonl(INADDR_ANY); + if (resvp) { + if (bindresvport(so, &laddr) < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (verbose) { + fprintf(stderr, + "mount: Unable to bindresvport %s socket: errno %d (%s)\n", + p_prot == IPPROTO_UDP ? "UDP" : "TCP", + errno, strerror(errno)); + } + close(so); + return RPC_ANYSOCK; + } + } else { + cc = bind(so, (struct sockaddr *)&laddr, namelen); + if (cc < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (verbose) { + fprintf(stderr, + "mount: Unable to bind to %s socket: errno %d (%s)\n", + p_prot == IPPROTO_UDP ? "UDP" : "TCP", + errno, strerror(errno)); + } + close(so); + return RPC_ANYSOCK; + } + } + if (type == SOCK_STREAM) { + cc = connect(so, (struct sockaddr *)saddr, namelen); + if (cc < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (verbose) { + fprintf(stderr, + "mount: Unable to connect to %s:%d, errno %d (%s)\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port), + errno, strerror(errno)); + } + close(so); + return RPC_ANYSOCK; + } + } + return so; +} + +/* + * 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 u_long prog, const u_long vers, + const u_int prot) +{ + CLIENT *clnt=NULL; + int sock, stat; + static char clnt_res; + + rpc_createerr.cf_stat = stat = errno = 0; + sock = get_socket(saddr, prot, FALSE); + if (sock == RPC_ANYSOCK && errno == ETIMEDOUT) { + /* + * TCP timeout. Bubble up the error to see + * how it should be handled. + */ + rpc_createerr.cf_stat = RPC_TIMEDOUT; + goto out_bad; + } + + switch(prot) { + case IPPROTO_UDP: + 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; + default: + goto out_bad; + } + if (!clnt) + goto out_bad; + 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); + if (sock != -1) + close(sock); + + if (stat == RPC_SUCCESS) + return 1; + + out_bad: + return 0; +} + +CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) +{ + struct sockaddr_in *mnt_saddr = &mnt_server->saddr; + struct pmap *mnt_pmap = &mnt_server->pmap; + CLIENT *clnt = NULL; + + /* contact the mount daemon via TCP */ + mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port); + *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE); + + switch (mnt_pmap->pm_prot) { + case IPPROTO_UDP: + clnt = clntudp_bufcreate(mnt_saddr, + mnt_pmap->pm_prog, mnt_pmap->pm_vers, + RETRY_TIMEOUT, msock, + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); + break; + case IPPROTO_TCP: + clnt = clnttcp_create(mnt_saddr, + mnt_pmap->pm_prog, mnt_pmap->pm_vers, + msock, + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); + break; + } + if (clnt) { + /* try to mount hostname:dirname */ + clnt->cl_auth = authunix_create_default(); + return clnt; + } + return NULL; +} + +void mnt_closeclnt(CLIENT *clnt, int msock) +{ + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + close(msock); +} + |