From: Chuck Lever Date: Mon, 16 Jul 2007 20:28:46 +0000 (-0400) Subject: mount.nfs: Move network functions into a common source module X-Git-Tag: nfs-utils-1-1-1~143 X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=commitdiff_plain;h=0dfc8a5426381c6d65aed4d9d0e50bae3238cc8f mount.nfs: Move network functions into a common source module Separate network oriented functions from filesystem oriented functions, for general cleanliness. Signed-off-by: Chuck Lever Signed-off-by: Neil Brown --- diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am index ea1a01e..be83e2c 100644 --- a/utils/mount/Makefile.am +++ b/utils/mount/Makefile.am @@ -9,10 +9,10 @@ man5_MANS = nfs.man sbin_PROGRAMS = mount.nfs EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS) -mount_nfs_SOURCES = mount.c error.c \ +mount_nfs_SOURCES = mount.c error.c network.c \ nfsmount.c nfs4mount.c \ nfsumount.c \ - mount_constants.h error.h \ + mount_constants.h error.h network.h \ nfs4_mount.h nfs_mount4.h mount_nfs_LDADD = ../../support/nfs/libnfs.a \ diff --git a/utils/mount/mount.c b/utils/mount/mount.c index 96b5697..30946bd 100644 --- a/utils/mount/mount.c +++ b/utils/mount/mount.c @@ -42,6 +42,7 @@ #include "nfsumount.h" #include "mount.h" #include "error.h" +#include "network.h" char *progname; int nfs_mount_data_version; @@ -350,12 +351,6 @@ static int chk_mountpoint(char *mount_point) return 0; } -extern u_short getport( - struct sockaddr_in *saddr, - u_long prog, - u_long vers, - u_int prot); - static int probe_statd() { struct sockaddr_in addr; diff --git a/utils/mount/network.c b/utils/mount/network.c new file mode 100644 index 0000000..c11fa3e --- /dev/null +++ b/utils/mount/network.c @@ -0,0 +1,318 @@ +/* + * network.c -- Provide common network functions for NFS mount/umount + * + * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2007 Chuck Lever + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conn.h" +#include "xcommon.h" +#include "mount.h" +#include "nls.h" +#include "nfsumount.h" +#include "nfs_mount.h" +#include "mount_constants.h" +#include "network.h" + +#ifdef HAVE_RPCSVC_NFS_PROT_H +#include +#else +#include +#define nfsstat nfs_stat +#endif + +#ifndef NFS_PORT +#define NFS_PORT 2049 +#endif + +extern int nfs_mount_data_version; +extern char *progname; +extern int verbose; + +static const unsigned int probe_udp_only[] = { + IPPROTO_UDP, + 0, +}; + +static const unsigned int probe_udp_first[] = { + IPPROTO_UDP, + IPPROTO_TCP, + 0, +}; + +static const unsigned int probe_tcp_first[] = { + IPPROTO_TCP, + IPPROTO_UDP, + 0, +}; + +static const unsigned long probe_nfs2_only[] = { + 2, + 0, +}; + +static const unsigned long probe_nfs3_first[] = { + 3, + 2, + 0, +}; + +static const unsigned long probe_mnt1_first[] = { + 1, + 2, + 0, +}; + +static const unsigned long probe_mnt3_first[] = { + 3, + 1, + 2, + 0, +}; + +int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr) +{ + struct hostent *hp; + + saddr->sin_family = AF_INET; + if (!inet_aton(hostname, &saddr->sin_addr)) { + if ((hp = gethostbyname(hostname)) == NULL) { + nfs_error(_("mount: can't get address for %s\n"), + hostname); + return 0; + } else { + if (hp->h_length > sizeof(*saddr)) { + nfs_error(_("mount: got bad hp->h_length\n")); + hp->h_length = sizeof(*saddr); + } + memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length); + } + } + return 1; +} + +/* + * getport() is very similar to pmap_getport() with + * the exception this version uses a non-reserve ports + * instead of reserve ports since reserve ports + * are not needed for pmap requests. + */ +unsigned short getport(struct sockaddr_in *saddr, unsigned long prog, + unsigned long vers, unsigned int prot) +{ + unsigned short port = 0; + int socket; + CLIENT *clnt = NULL; + struct pmap parms; + enum clnt_stat stat; + + saddr->sin_port = htons (PMAPPORT); + socket = get_socket(saddr, prot, FALSE, FALSE); + + switch (prot) { + case IPPROTO_UDP: + clnt = clntudp_bufcreate(saddr, + PMAPPROG, PMAPVERS, TIMEOUT, &socket, + UDPMSGSIZE, UDPMSGSIZE); + break; + case IPPROTO_TCP: + clnt = clnttcp_create(saddr, + PMAPPROG, PMAPVERS, &socket, 50, 500); + break; + } + if (clnt != NULL) { + parms.pm_prog = prog; + parms.pm_vers = vers; + parms.pm_prot = prot; + parms.pm_port = 0; /* not needed or used */ + + stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap, + (caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT); + if (stat) { + clnt_geterr(clnt, &rpc_createerr.cf_error); + rpc_createerr.cf_stat = stat; + } + clnt_destroy(clnt); + if (stat != RPC_SUCCESS) + port = 0; + else if (port == 0) + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + } + if (socket != 1) + close(socket); + + return port; +} + +/* + * Use the portmapper to discover whether or not the service we want is + * available. The lists 'versions' and 'protos' define ordered sequences + * of service versions and udp/tcp protocols to probe for. + */ +static int probe_port(clnt_addr_t *server, const unsigned long *versions, + const unsigned int *protos) +{ + struct sockaddr_in *saddr = &server->saddr; + struct pmap *pmap = &server->pmap; + const unsigned long prog = pmap->pm_prog, *p_vers; + const unsigned int prot = (u_int)pmap->pm_prot, *p_prot; + const u_short port = (u_short) pmap->pm_port; + unsigned long vers = pmap->pm_vers; + unsigned short p_port; + + p_prot = prot ? &prot : protos; + p_vers = vers ? &vers : versions; + rpc_createerr.cf_stat = 0; + for (;;) { + saddr->sin_port = htons(PMAPPORT); + p_port = getport(saddr, prog, *p_vers, *p_prot); + if (p_port) { + if (!port || port == p_port) { + saddr->sin_port = htons(p_port); + if (verbose) { + printf(_("%s: trying %s prog %ld vers " + "%ld prot %s port %d\n"), + progname, + inet_ntoa(saddr->sin_addr), + prog, *p_vers, + *p_prot == IPPROTO_UDP ? + "udp" : "tcp", + p_port); + } + if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL)) + goto out_ok; + if (rpc_createerr.cf_stat == RPC_TIMEDOUT) + goto out_bad; + } + } + if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) + goto out_bad; + + if (!prot) { + if (*++p_prot) + continue; + p_prot = protos; + } + if (vers == pmap->pm_vers) { + p_vers = versions; + vers = 0; + } + if (vers || !*++p_vers) + break; + } + +out_bad: + return 0; + +out_ok: + if (!vers) + pmap->pm_vers = *p_vers; + if (!prot) + pmap->pm_prot = *p_prot; + if (!port) + pmap->pm_port = p_port; + rpc_createerr.cf_stat = 0; + return 1; +} + +int probe_nfsport(clnt_addr_t *nfs_server) +{ + struct pmap *pmap = &nfs_server->pmap; + + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) + return 1; + + if (nfs_mount_data_version >= 4) + return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first); + else + return probe_port(nfs_server, probe_nfs2_only, probe_udp_only); +} + +int probe_mntport(clnt_addr_t *mnt_server) +{ + struct pmap *pmap = &mnt_server->pmap; + + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) + return 1; + + if (nfs_mount_data_version >= 4) + return probe_port(mnt_server, probe_mnt3_first, probe_udp_first); + else + return probe_port(mnt_server, probe_mnt1_first, probe_udp_only); +} + +int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) +{ + struct pmap *nfs_pmap = &nfs_server->pmap; + struct pmap *mnt_pmap = &mnt_server->pmap; + struct pmap save_nfs, save_mnt; + int res; + const unsigned long *probe_vers; + + if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers) + nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers); + else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers) + mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers); + if (nfs_pmap->pm_vers) + goto version_fixed; + + memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs)); + memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt)); + probe_vers = (nfs_mount_data_version >= 4) ? + probe_mnt3_first : probe_mnt1_first; + + for (; *probe_vers; probe_vers++) { + nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers); + if ((res = probe_nfsport(nfs_server) != 0)) { + mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers); + if ((res = probe_mntport(mnt_server)) != 0) + return 1; + memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap)); + } + switch (rpc_createerr.cf_stat) { + case RPC_PROGVERSMISMATCH: + case RPC_PROGNOTREGISTERED: + break; + default: + goto out_bad; + } + memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap)); + } + +out_bad: + return 0; + +version_fixed: + if (!probe_nfsport(nfs_server)) + goto out_bad; + return probe_mntport(mnt_server); +} diff --git a/utils/mount/network.h b/utils/mount/network.h new file mode 100644 index 0000000..3a2fa7c --- /dev/null +++ b/utils/mount/network.h @@ -0,0 +1,31 @@ +/* + * network.h -- Provide common network functions for NFS mount/umount + * + * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2007 Chuck Lever + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + */ + +#include "conn.h" + +int nfs_gethostbyname(const char *, struct sockaddr_in *); +unsigned short getport(struct sockaddr_in *, unsigned long, + unsigned long, unsigned int); +int probe_mntport(clnt_addr_t *); +int probe_nfsport(clnt_addr_t *); +int probe_bothports(clnt_addr_t *, clnt_addr_t *); diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c index 4b862f0..9c08ff5 100644 --- a/utils/mount/nfsmount.c +++ b/utils/mount/nfsmount.c @@ -64,6 +64,7 @@ #include "mount_constants.h" #include "nls.h" #include "error.h" +#include "network.h" #ifndef NFS_PORT #define NFS_PORT 2049 @@ -93,269 +94,6 @@ extern int sloppy; extern int linux_version_code(); -static const unsigned int probe_udp_only[] = { - IPPROTO_UDP, - 0, -}; - -static const unsigned int probe_udp_first[] = { - IPPROTO_UDP, - IPPROTO_TCP, - 0, -}; - -static const unsigned int probe_tcp_first[] = { - IPPROTO_TCP, - IPPROTO_UDP, - 0, -}; - -static const unsigned long probe_nfs2_only[] = { - 2, - 0, -}; - -static const unsigned long probe_nfs3_first[] = { - 3, - 2, - 0, -}; - -static const unsigned long probe_mnt1_first[] = { - 1, - 2, - 0, -}; - -static const unsigned long probe_mnt3_first[] = { - 3, - 1, - 2, - 0, -}; - -int nfs_gethostbyname(const char *, struct sockaddr_in *); -int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr) -{ - struct hostent *hp; - - saddr->sin_family = AF_INET; - if (!inet_aton(hostname, &saddr->sin_addr)) { - if ((hp = gethostbyname(hostname)) == NULL) { - fprintf(stderr, _("mount: can't get address for %s\n"), - hostname); - return 0; - } else { - if (hp->h_length > sizeof(*saddr)) { - fprintf(stderr, - _("mount: got bad hp->h_length\n")); - hp->h_length = sizeof(*saddr); - } - memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length); - } - } - return 1; -} - -/* - * getport() is very similar to pmap_getport() with - * the exception this version uses a non-reserve ports - * instead of reserve ports since reserve ports - * are not needed for pmap requests. - */ -u_short -getport( - struct sockaddr_in *saddr, - u_long prog, - u_long vers, - u_int prot) -{ - u_short port = 0; - int socket; - CLIENT *clnt = NULL; - struct pmap parms; - enum clnt_stat stat; - - saddr->sin_port = htons (PMAPPORT); - socket = get_socket(saddr, prot, FALSE, FALSE); - - switch (prot) { - case IPPROTO_UDP: - clnt = clntudp_bufcreate(saddr, - PMAPPROG, PMAPVERS, TIMEOUT, &socket, - UDPMSGSIZE, UDPMSGSIZE); - break; - case IPPROTO_TCP: - clnt = clnttcp_create(saddr, - PMAPPROG, PMAPVERS, &socket, 50, 500); - break; - } - if (clnt != NULL) { - parms.pm_prog = prog; - parms.pm_vers = vers; - parms.pm_prot = prot; - parms.pm_port = 0; /* not needed or used */ - - stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap, - (caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT); - if (stat) { - clnt_geterr(clnt, &rpc_createerr.cf_error); - rpc_createerr.cf_stat = stat; - } - clnt_destroy(clnt); - if (stat != RPC_SUCCESS) - port = 0; - else if (port == 0) - rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; - } - if (socket != 1) - close(socket); - - return port; -} - -/* - * Use the portmapper to discover whether or not the service we want is - * available. The lists 'versions' and 'protos' define ordered sequences - * of service versions and udp/tcp protocols to probe for. - */ -static int -probe_port(clnt_addr_t *server, - const u_long *versions, - const u_int *protos) -{ - struct sockaddr_in *saddr = &server->saddr; - struct pmap *pmap = &server->pmap; - const u_long prog = pmap->pm_prog, *p_vers; - const u_int prot = (u_int)pmap->pm_prot, - *p_prot; - const u_short port = (u_short) pmap->pm_port; - u_long vers = pmap->pm_vers; - u_short p_port; - p_prot = prot ? &prot : protos; - p_vers = vers ? &vers : versions; - rpc_createerr.cf_stat = 0; - for (;;) { - saddr->sin_port = htons(PMAPPORT); - p_port = getport(saddr, prog, *p_vers, *p_prot); - if (p_port) { - if (!port || port == p_port) { - saddr->sin_port = htons(p_port); - if (verbose) { - fprintf(stderr, - "mount: trying %s prog %ld vers %ld prot %s port %d\n", - inet_ntoa(saddr->sin_addr), prog, *p_vers, - *p_prot == IPPROTO_UDP ? "udp" : "tcp", p_port); - } - if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL)) - goto out_ok; - if (rpc_createerr.cf_stat == RPC_TIMEDOUT) - goto out_bad; - } - } - if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) - goto out_bad; - - if (!prot) { - if (*++p_prot) - continue; - p_prot = protos; - } - if (vers == pmap->pm_vers) { - p_vers = versions; - vers = 0; - } - if (vers || !*++p_vers) - break; - } -out_bad: - return 0; - - out_ok: - if (!vers) - pmap->pm_vers = *p_vers; - if (!prot) - pmap->pm_prot = *p_prot; - if (!port) - pmap->pm_port = p_port; - rpc_createerr.cf_stat = 0; - return 1; -} - -static int probe_nfsport(clnt_addr_t *nfs_server) -{ - struct pmap *pmap = &nfs_server->pmap; - - if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) - return 1; - - if (nfs_mount_data_version >= 4) - return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first); - else - return probe_port(nfs_server, probe_nfs2_only, probe_udp_only); -} - -int probe_mntport(clnt_addr_t *mnt_server) -{ - struct pmap *pmap = &mnt_server->pmap; - - if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) - return 1; - - if (nfs_mount_data_version >= 4) - return probe_port(mnt_server, probe_mnt3_first, probe_udp_first); - else - return probe_port(mnt_server, probe_mnt1_first, probe_udp_only); -} - -static int -probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) -{ - struct pmap *nfs_pmap = &nfs_server->pmap; - struct pmap *mnt_pmap = &mnt_server->pmap; - struct pmap save_nfs, save_mnt; - int res; - const unsigned long *probe_vers; - - if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers) - nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers); - else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers) - mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers); - if (nfs_pmap->pm_vers) - goto version_fixed; - - memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs)); - memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt)); - probe_vers = (nfs_mount_data_version >= 4) ? - probe_mnt3_first : probe_mnt1_first; - - for (; *probe_vers; probe_vers++) { - nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers); - if ((res = probe_nfsport(nfs_server) != 0)) { - mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers); - if ((res = probe_mntport(mnt_server)) != 0) - return 1; - memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap)); - } - switch (rpc_createerr.cf_stat) { - case RPC_PROGVERSMISMATCH: - case RPC_PROGNOTREGISTERED: - break; - default: - goto out_bad; - } - memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap)); - } - -out_bad: - return 0; - -version_fixed: - if (!probe_nfsport(nfs_server)) - goto out_bad; - return probe_mntport(mnt_server); -} - static inline enum clnt_stat nfs3_mount(CLIENT *clnt, mnt3arg_t *mnt3arg, mnt3res_t *mnt3res) { diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c index 91d0e85..97b96e8 100644 --- a/utils/mount/nfsumount.c +++ b/utils/mount/nfsumount.c @@ -35,6 +35,7 @@ #include "mount.h" #include "nfsumount.h" #include "error.h" +#include "network.h" #if !defined(MNT_FORCE) /* dare not try to include -- lots of errors */ @@ -52,9 +53,6 @@ int force; int lazy; int remount; -extern int probe_mntport(clnt_addr_t *); -extern int nfs_gethostbyname(const char *, struct sockaddr_in *); - static inline enum clnt_stat nfs_umount(dirpath *argp, CLIENT *clnt) {