}
}
-#ifdef HAVE_DECL_AI_ADDRCONFIG
-/**
- * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
- * @hostname: pointer to C string containing DNS hostname to resolve
- * @af_hint: hint to restrict resolution to one address family
- * @sap: pointer to buffer to fill with socket address
- * @len: IN: size of buffer to fill; OUT: size of socket address
- *
- * Returns 1 and places a socket address at @sap if successful;
- * otherwise zero.
- */
-int nfs_name_to_address(const char *hostname,
- const sa_family_t af_hint,
- struct sockaddr *sap, socklen_t *salen)
+static int nfs_lookup(const char *hostname, const sa_family_t family,
+ struct sockaddr *sap, socklen_t *salen)
{
struct addrinfo *gai_results;
struct addrinfo gai_hint = {
- .ai_family = af_hint,
+#ifdef HAVE_DECL_AI_ADDRCONFIG
.ai_flags = AI_ADDRCONFIG,
+#endif /* HAVE_DECL_AI_ADDRCONFIG */
+ .ai_family = family,
};
socklen_t len = *salen;
int error, ret = 0;
- if (af_hint == AF_INET6)
- gai_hint.ai_flags |= AI_V4MAPPED|AI_ALL;
-
*salen = 0;
error = getaddrinfo(hostname, NULL, &gai_hint, &gai_results);
- if (error) {
+ switch (error) {
+ case 0:
+ break;
+ case EAI_SYSTEM:
+ nfs_error(_("%s: DNS resolution failed for %s: %s"),
+ progname, hostname, strerror(errno));
+ return ret;
+ default:
nfs_error(_("%s: DNS resolution failed for %s: %s"),
- progname, hostname, (error == EAI_SYSTEM ?
- strerror(errno) : gai_strerror(error)));
+ progname, hostname, gai_strerror(error));
return ret;
}
freeaddrinfo(gai_results);
return ret;
}
-#else /* HAVE_DECL_AI_ADDRCONFIG */
+
/**
- * nfs_name_to_address - resolve hostname to an IPv4 socket address
+ * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
* @hostname: pointer to C string containing DNS hostname to resolve
- * @af_hint: hint to restrict resolution to one address family
* @sap: pointer to buffer to fill with socket address
* @len: IN: size of buffer to fill; OUT: size of socket address
*
* Returns 1 and places a socket address at @sap if successful;
* otherwise zero.
- *
- * Some older getaddrinfo(3) implementations don't support
- * AI_ADDRCONFIG or AI_V4MAPPED properly. For those cases, a DNS
- * resolver based on the traditional gethostbyname(3) is provided.
*/
int nfs_name_to_address(const char *hostname,
- const sa_family_t af_hint,
struct sockaddr *sap, socklen_t *salen)
{
- struct sockaddr_in *sin = (struct sockaddr_in *)sap;
- socklen_t len = *salen;
- struct hostent *hp;
-
- *salen = 0;
-
- if (af_hint != AF_INET) {
- nfs_error(_("%s: address family not supported by DNS resolver\n"),
- progname, hostname);
- return 0;
- }
-
- sin->sin_family = AF_INET;
- if (inet_aton(hostname, &sin->sin_addr)) {
- *salen = sizeof(*sin);
- return 1;
- }
-
- hp = gethostbyname(hostname);
- if (hp == NULL) {
- nfs_error(_("%s: DNS resolution failed for %s: %s"),
- progname, hostname, hstrerror(h_errno));
- return 0;
- }
-
- if (hp->h_length > len) {
- nfs_error(_("%s: DNS resolution results too long for buffer\n"),
- progname);
- return 0;
- }
-
- memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
- *salen = hp->h_length;
- return 1;
+#ifdef IPV6_SUPPORTED
+ return nfs_lookup(hostname, AF_UNSPEC, sap, salen);
+#else /* !IPV6_SUPPORTED */
+ return nfs_lookup(hostname, AF_INET, sap, salen);
+#endif /* !IPV6_SUPPORTED */
}
-#endif /* HAVE_DECL_AI_ADDRCONFIG */
/**
* nfs_gethostbyname - resolve a hostname to an IPv4 address
{
socklen_t len = sizeof(*sin);
- return nfs_name_to_address(hostname, AF_INET,
- (struct sockaddr *)sin, &len);
+ return nfs_lookup(hostname, AF_INET, (struct sockaddr *)sin, &len);
}
/**
strcat(buf, "unknown host");
}
- fprintf(stderr, _("%s: trying %s prog %ld vers %ld prot %s port %d\n"),
- progname, buf, program, version,
+ fprintf(stderr, _("%s: trying %s prog %lu vers %lu prot %s port %d\n"),
+ progname, buf, (unsigned long)program,
+ (unsigned long)version,
(protocol == IPPROTO_UDP ? _("UDP") : _("TCP")),
port);
}
return 0;
}
+/**
+ * nfs_advise_umount - ask the server to remove a share from it's rmtab
+ * @sap: pointer to IP address of server to call
+ * @salen: length of server address
+ * @pmap: partially filled-in mountd RPC service tuple
+ * @argp: directory path of share to "unmount"
+ *
+ * Returns one if the unmount call succeeded; zero if the unmount
+ * failed for any reason; rpccreateerr.cf_stat is set to reflect
+ * the nature of the error.
+ *
+ * We use a fast timeout since this call is advisory only.
+ */
+int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
+ const struct pmap *pmap, const dirpath *argp)
+{
+ struct sockaddr_storage address;
+ struct sockaddr *saddr = (struct sockaddr *)&address;
+ struct pmap mnt_pmap = *pmap;
+ struct timeval timeout = {
+ .tv_sec = MOUNT_TIMEOUT >> 3,
+ };
+ CLIENT *client;
+ enum clnt_stat res = 0;
+
+ if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0)
+ return 0;
+
+ memcpy(saddr, sap, salen);
+ nfs_set_port(saddr, mnt_pmap.pm_port);
+
+ client = nfs_get_priv_rpcclient(saddr, salen, mnt_pmap.pm_prot,
+ mnt_pmap.pm_prog, mnt_pmap.pm_vers,
+ &timeout);
+ if (client == NULL)
+ return 0;
+
+ client->cl_auth = authunix_create_default();
+
+ res = CLNT_CALL(client, MOUNTPROC_UMNT,
+ (xdrproc_t)xdr_dirpath, (caddr_t)argp,
+ (xdrproc_t)xdr_void, NULL,
+ timeout);
+
+ auth_destroy(client->cl_auth);
+ CLNT_DESTROY(client);
+
+ if (res != RPC_SUCCESS)
+ return 0;
+
+ return 1;
+}
+
/**
* nfs_call_umount - ask the server to remove a share from it's rmtab
* @mnt_server: address of RPC MNT program server
return IPPROTO_UDP;
}
- return nfs_nfs_version(options);
+ return nfs_nfs_protocol(options);
}
/*