Here's my first stab at a patch for mount to make it treat the addr=
option as a hint. I've done some very basic testing and it seems to do
the right thing, but I need to dredge up a multi-homed NFS server here
soon to verify that all is working. If anyone has one and wants to test
this out for me, I'd be appreciative :-)

The patch is a little larger than I had originally anticipated,
primarily because I had to move a chunk of code that happened before the
option parsing to after.

Since the util-linux mailing list seems to be inactive, should I just
submit this to the util-linux maintainer directly?

-- Jeff

Index: util-linux/mount/nfsmount.c
===================================================================
--- util-linux/mount/nfsmount.c	(revision 170)
+++ util-linux/mount/nfsmount.c	(working copy)
@@ -195,7 +195,7 @@
 	static char *prev_bg_host;
 	char hostdir[1024];
 	CLIENT *mclient;
-	char *hostname, *dirname, *old_opts, *mounthost = NULL;
+	char *hostname, *dirname, *old_opts, *mounthost, *prefaddr_s = NULL;
 	char new_opts[1024];
 	struct timeval total_timeout;
 	enum clnt_stat clnt_stat;
@@ -207,6 +207,7 @@
 	struct sockaddr_in server_addr;
 	struct sockaddr_in mount_server_addr;
 	struct pmap *pm_mnt;
+	struct in_addr prefaddr;
 	int msock, fsock;
 	struct timeval retry_timeout;
 	union {
@@ -214,7 +215,7 @@
 		struct mountres3 nfsv3;
 	} status;
 	struct stat statbuf;
-	char *s;
+	char *s = NULL;
 	int port, mountport, proto, bg, soft, intr;
 	int posix, nocto, noac, nolock, broken_suid;
 	int retry, tcp;
@@ -258,43 +259,6 @@
 		goto fail;
 	}
 
-	server_addr.sin_family = AF_INET;
-#ifdef HAVE_inet_aton
-	if (!inet_aton(hostname, &server_addr.sin_addr))
-#endif
-	{
-		if ((hp = gethostbyname(hostname)) == NULL) {
-			fprintf(stderr, _("mount: can't get address for %s\n"),
-				hostname);
-			goto fail;
-		} else {
-			if (hp->h_length > sizeof(struct in_addr)) {
-				fprintf(stderr,
-					_("mount: got bad hp->h_length\n"));
-				hp->h_length = sizeof(struct in_addr);
-			}
-			memcpy(&server_addr.sin_addr,
-			       hp->h_addr, hp->h_length);
-		}
-	}
-
-	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
-
-	/* add IP address to mtab options for use when unmounting */
-
-	s = inet_ntoa(server_addr.sin_addr);
-	old_opts = *extra_opts;
-	if (!old_opts)
-		old_opts = "";
-	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
-		fprintf(stderr, _("mount: "
-				  "excessively long option argument\n"));
-		goto fail;
-	}
-	sprintf(new_opts, "%s%saddr=%s",
-		old_opts, *old_opts ? "," : "", s);
-	*extra_opts = xstrdup(new_opts);
-
 	/* Set default options.
 	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
 	 * let the kernel decide.
@@ -328,6 +292,7 @@
 	nfsvers = 0;
 
 	/* parse options */
+	old_opts = xstrdup(*extra_opts);
 
 	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
 		if ((opteq = strchr(opt, '='))) {
@@ -388,10 +353,10 @@
 #endif
 					printf(_("Warning: Option namlen is not supported.\n"));
 			} else if (!strcmp(opt, "addr")) {
-				/* ignore */;
+				prefaddr_s = opteq + 1;
 			} else {
 				printf(_("unknown nfs mount parameter: "
-					 "%s=%d\n"), opt, val);
+					 "%s=%s\n"), opt, opteq+1);
 				goto fail;
 			}
 		} else {
@@ -477,8 +442,8 @@
 	       data.rsize, data.wsize, data.timeo, data.retrans);
 	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
 	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
-	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
-	       port, bg, retry, data.flags);
+	printf("port = %d, bg = %d, retry = %d, flags = %.8x, addr = %s\n",
+	       port, bg, retry, data.flags, prefaddr_s);
 	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
 	       mountprog, mountvers, nfsprog, nfsvers);
 	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
@@ -511,6 +476,78 @@
 		return retval;
 	}
 
+	s = NULL;
+	server_addr.sin_family = AF_INET;
+#ifdef HAVE_inet_aton
+	if (!inet_aton(hostname, &server_addr.sin_addr))
+#endif
+	{
+		if ((hp = gethostbyname(hostname)) == NULL) {
+			fprintf(stderr, _("mount: can't get address for %s\n"),
+				hostname);
+			goto fail;
+		} else {
+			if (hp->h_length > sizeof(struct in_addr)) {
+				fprintf(stderr,
+					_("mount: got bad hp->h_length\n"));
+				hp->h_length = sizeof(struct in_addr);
+			}
+
+			val = 0;
+			s = NULL;
+
+#ifdef HAVE_inet_aton
+			/* if a preferred address is specified, then make sure
+			 * it matches one of the host's addresses before using
+			 * it. If it doesn't, just use first host in list.
+			 */
+			if (prefaddr_s) {
+				inet_aton(prefaddr_s,&prefaddr);
+				while(hp->h_addr_list[val]) {
+					if (prefaddr.s_addr == *(ulong *)
+						(hp->h_addr_list[val])) {
+						s = hp->h_addr_list[val];
+						break;
+					}
+					++val;
+				}
+
+				if (!s)
+					fprintf(stderr, _("mount: specified address doesn't match hostname. Ignoring it.\n"));
+			}
+#endif /* HAVE_inet_aton */
+
+			if (s) {
+				memcpy(&server_addr.sin_addr,
+			       		s, hp->h_length);
+			} else {
+				memcpy(&server_addr.sin_addr,
+			       		hp->h_addr, hp->h_length);
+			}
+		}
+	}
+
+	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
+
+	/* add IP address to mtab options for use when unmounting, if it
+	 * wasn't specified or was ignored */
+	if (!s) {
+		s = inet_ntoa(server_addr.sin_addr);
+		old_opts = *extra_opts;
+
+		if (!old_opts)
+			old_opts = "";
+
+		if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
+			fprintf(stderr, _("mount: "
+				  "excessively long option argument\n"));
+			goto fail;
+		}
+		sprintf(new_opts, "%s%saddr=%s",
+			old_opts, *old_opts ? "," : "", s);
+		*extra_opts = xstrdup(new_opts);
+	}
+
 	/* create mount deamon client */
 	/* See if the nfs host = mount host. */
 	if (mounthost) {
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs

Reply via email to