blob: 8247a1ad568376e1afd2486c04fd0eaa81e0eaa9 [file] [log] [blame]
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 751f9b8..b2e4374 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -33,11 +33,13 @@
#include <errno.h>
#include <netdb.h>
#include <time.h>
+#include <grp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
+#include <linux/in6.h>
#include <netinet/in.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
@@ -802,6 +804,7 @@ int start_statd(void)
pid_t pid = fork();
switch (pid) {
case 0: /* child */
+ setgroups(0, NULL);
setgid(0);
setuid(0);
execle(START_STATD, START_STATD, NULL, envp);
@@ -1112,6 +1115,7 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
.sin6_addr = IN6ADDR_ANY_INIT,
};
int sock, result = 0;
+ int val;
sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
@@ -1123,6 +1127,9 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
goto out;
break;
case AF_INET6:
+ /* Make sure the call-back address is public/permanent */
+ val = IPV6_PREFER_SRC_PUBLIC;
+ setsockopt(sock, SOL_IPV6, IPV6_ADDR_PREFERENCES, &val, sizeof(val));
if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0)
goto out;
break;
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index fc68d41..57e932f 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -91,6 +91,7 @@ struct nfsmount_info {
*type; /* "nfs" or "nfs4" */
char *hostname; /* server's hostname */
struct addrinfo *address; /* server's addresses */
+ sa_family_t family; /* Address family */
struct mount_options *options; /* parsed mount options */
char **extra_opts; /* string for /etc/mtab */
@@ -388,39 +389,19 @@ static int nfs_set_version(struct nfsmount_info *mi)
*/
static int nfs_validate_options(struct nfsmount_info *mi)
{
- struct addrinfo hint = {
- .ai_protocol = (int)IPPROTO_UDP,
- };
- sa_family_t family;
- int error;
-
if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL))
return 0;
- if (!nfs_nfs_proto_family(mi->options, &family))
+ if (!nfs_nfs_proto_family(mi->options, &mi->family))
return 0;
/*
* A remount is not going to be able to change the server's address,
* nor should we try to resolve another address for the server as we
* may end up with a different address.
+ * A non-remount will set 'addr' from ->hostname
*/
- if (mi->flags & MS_REMOUNT) {
- po_remove_all(mi->options, "addr");
- } else {
- hint.ai_family = (int)family;
- error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address);
- if (error != 0) {
- nfs_error(_("%s: Failed to resolve server %s: %s"),
- progname, mi->hostname, gai_strerror(error));
- mi->address = NULL;
- return 0;
- }
-
- if (!nfs_append_addr_option(mi->address->ai_addr,
- mi->address->ai_addrlen, mi->options))
- return 0;
- }
+ po_remove_all(mi->options, "addr");
if (!nfs_set_version(mi))
return 0;
@@ -900,7 +881,10 @@ check_result:
result = nfs_try_mount_v4(mi);
if (result == 0 && errno != ECONNREFUSED)
goto check_result;
- }
+ } else if (result == 0)
+ /* Restore original errno with v3 failures */
+ errno = ECONNREFUSED;
+
return result;
default:
return result;
@@ -923,6 +907,32 @@ static int nfs_try_mount(struct nfsmount_info *mi)
{
int result = 0;
+ if (mi->address == NULL) {
+ struct addrinfo hint = {
+ .ai_protocol = (int)IPPROTO_UDP,
+ };
+ int error;
+ struct addrinfo *address;
+
+ hint.ai_family = (int)mi->family;
+ error = getaddrinfo(mi->hostname, NULL, &hint, &address);
+ if (error != 0) {
+ if (error == EAI_AGAIN)
+ errno = EAGAIN;
+ else {
+ nfs_error(_("%s: Failed to resolve server %s: %s"),
+ progname, mi->hostname, gai_strerror(error));
+ errno = EALREADY;
+ }
+ return 0;
+ }
+
+ if (!nfs_append_addr_option(address->ai_addr,
+ address->ai_addrlen, mi->options))
+ return 0;
+ mi->address = address;
+ }
+
switch (mi->version.major) {
case 2:
case 3:
@@ -1018,10 +1028,8 @@ static int nfsmount_fg(struct nfsmount_info *mi)
if (nfs_is_permanent_error(errno))
break;
- if (time(NULL) > timeout) {
- errno = ETIMEDOUT;
+ if (time(NULL) > timeout)
break;
- }
if (errno != ETIMEDOUT) {
if (sleep(secs))