walters / rpms / nfs-utils

Forked from rpms/nfs-utils 6 years ago
Clone
e237fe4
text-based mount command: make po_rightmost() work for N options
e237fe4
e237fe4
Sometimes we need to choose the rightmost option among multiple
e237fe4
different mount options.  For example, we want to find the rightmost
e237fe4
of "proto," "tcp," and "udp".  Or, the rightmost of "vers," "nfsvers,"
e237fe4
"v2," and "v3".
e237fe4
e237fe4
Update po_rightmost() to choose among N options instead of just two.
e237fe4
e237fe4
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
e237fe4
---
e237fe4
e237fe4
 utils/mount/parse_opt.c |   28 ++++++++++++++++------------
e237fe4
 utils/mount/parse_opt.h |    9 ++-------
e237fe4
 utils/mount/stropts.c   |   28 +++++++++++++++++++++++-----
e237fe4
 3 files changed, 41 insertions(+), 24 deletions(-)
e237fe4
e237fe4
diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c
e237fe4
index f61d0dd..4934508 100644
e237fe4
--- a/utils/mount/parse_opt.c
e237fe4
+++ b/utils/mount/parse_opt.c
e237fe4
@@ -421,34 +421,38 @@ po_found_t po_get_numeric(struct mount_options *options, char *keyword, long *va
e237fe4
 #endif	/* HAVE_STRTOL */
e237fe4
 
e237fe4
 /**
e237fe4
- * po_rightmost - determine the relative position of two options
e237fe4
+ * po_rightmost - determine the relative position of several options
e237fe4
  * @options: pointer to mount options
e237fe4
- * @key1: pointer to a C string containing an option keyword
e237fe4
- * @key2: pointer to a C string containing another option keyword
e237fe4
+ * @keys: pointer to an array of C strings containing option keywords
e237fe4
+ *
e237fe4
+ * This function can be used to determine which of several similar
e237fe4
+ * options will be the one to take effect.
e237fe4
  *
e237fe4
  * The kernel parses the mount option string from left to right.
e237fe4
  * If an option is specified more than once (for example, "intr"
e237fe4
  * and "nointr", the rightmost option is the last to be parsed,
e237fe4
  * and it therefore takes precedence over previous similar options.
e237fe4
  *
e237fe4
- * This function can be used to determine which of two similar
e237fe4
- * options will be the one to take effect.
e237fe4
+ * This can also distinguish among multiple synonymous options, such
e237fe4
+ * as "proto=," "udp" and "tcp."
e237fe4
+ *
e237fe4
+ * Returns the index into @keys of the option that is rightmost.
e237fe4
+ * If none of the options are present, returns zero.
e237fe4
  */
e237fe4
-po_rightmost_t po_rightmost(struct mount_options *options,
e237fe4
-			    char *key1, char *key2)
e237fe4
+unsigned int po_rightmost(struct mount_options *options, const char *keys[])
e237fe4
 {
e237fe4
 	struct mount_option *option;
e237fe4
+	unsigned int i;
e237fe4
 
e237fe4
 	if (options) {
e237fe4
 		for (option = options->tail; option; option = option->prev) {
e237fe4
-			if (key2 && strcmp(option->keyword, key2) == 0)
e237fe4
-				return PO_KEY2_RIGHTMOST;
e237fe4
-			if (key1 && strcmp(option->keyword, key1) == 0)
e237fe4
-				return PO_KEY1_RIGHTMOST;
e237fe4
+			for (i = 0; keys[i] != NULL; i++)
e237fe4
+				if (strcmp(option->keyword, keys[i]) == 0)
0b66620
+					return i;
e237fe4
 		}
e237fe4
 	}
e237fe4
 
e237fe4
-	return PO_NEITHER_FOUND;
e237fe4
+	return 0;
e237fe4
 }
e237fe4
 
e237fe4
 /**
e237fe4
diff --git a/utils/mount/parse_opt.h b/utils/mount/parse_opt.h
e237fe4
index 199630f..e132b1c 100644
e237fe4
--- a/utils/mount/parse_opt.h
e237fe4
+++ b/utils/mount/parse_opt.h
e237fe4
@@ -35,12 +35,6 @@ typedef enum {
e237fe4
 	PO_BAD_VALUE = 2,
e237fe4
 } po_found_t;
e237fe4
 
e237fe4
-typedef enum {
e237fe4
-	PO_KEY1_RIGHTMOST = -1,
e237fe4
-	PO_NEITHER_FOUND = 0,
e237fe4
-	PO_KEY2_RIGHTMOST = 1,
e237fe4
-} po_rightmost_t;
e237fe4
-
e237fe4
 struct mount_options;
e237fe4
 
e237fe4
 struct mount_options *	po_split(char *);
e237fe4
@@ -53,7 +47,8 @@ po_found_t		po_contains(struct mount_options *, char *);
e237fe4
 char *			po_get(struct mount_options *, char *);
e237fe4
 po_found_t		po_get_numeric(struct mount_options *,
e237fe4
 					char *, long *);
e237fe4
-po_rightmost_t		po_rightmost(struct mount_options *, char *, char *);
e237fe4
+unsigned int		po_rightmost(struct mount_options *,
e237fe4
+					const char *keys[]);
e237fe4
 po_found_t		po_remove_all(struct mount_options *, char *);
e237fe4
 void			po_destroy(struct mount_options *);
e237fe4
 
e237fe4
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
e237fe4
index 43791e6..bd127ab 100644
e237fe4
--- a/utils/mount/stropts.c
e237fe4
+++ b/utils/mount/stropts.c
e237fe4
@@ -224,9 +224,15 @@ static int nfs_fix_mounthost_option(const sa_family_t family,
e237fe4
  * Returns zero if the "lock" option is in effect, but statd
e237fe4
  * can't be started.  Otherwise, returns 1.
e237fe4
  */
e237fe4
+static const char *nfs_lock_opttbl[] = {
e237fe4
+	"nolock",
e237fe4
+	"lock",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
 static int nfs_verify_lock_option(struct mount_options *options)
e237fe4
 {
e237fe4
-	if (po_rightmost(options, "nolock", "lock") == PO_KEY1_RIGHTMOST)
e237fe4
+	if (po_rightmost(options, nfs_lock_opttbl) == 1)
e237fe4
 		return 1;
e237fe4
 
e237fe4
 	if (!start_statd()) {
e237fe4
@@ -316,6 +322,12 @@ static int nfs_is_permanent_error(int error)
e237fe4
  * Returns a new group of mount options if successful; otherwise
e237fe4
  * NULL is returned if some failure occurred.
e237fe4
  */
e237fe4
+static const char *nfs_transport_opttbl[] = {
e237fe4
+	"udp",
e237fe4
+	"tcp",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
 static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 {
e237fe4
 	struct mount_options *options;
e237fe4
@@ -395,12 +407,12 @@ static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 			po_remove_all(options, "proto");
e237fe4
 		}
e237fe4
 	}
e237fe4
-	p = po_rightmost(options, "tcp", "udp");
e237fe4
+	p = po_rightmost(options, nfs_transport_opttbl);
e237fe4
 	switch (p) {
e237fe4
-	case PO_KEY2_RIGHTMOST:
e237fe4
+	case 1:
e237fe4
 		nfs_server.pmap.pm_prot = IPPROTO_UDP;
e237fe4
 		break;
e237fe4
-	case PO_KEY1_RIGHTMOST:
e237fe4
+	case 2:
e237fe4
 		nfs_server.pmap.pm_prot = IPPROTO_TCP;
e237fe4
 		break;
e237fe4
 	}
e237fe4
@@ -722,12 +734,18 @@ static int nfsmount_bg(struct nfsmount_info *mi)
e237fe4
  *
e237fe4
  * Returns a valid mount command exit code.
e237fe4
  */
e237fe4
+static const char *nfs_background_opttbl[] = {
e237fe4
+	"bg",
e237fe4
+	"fg",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
 static int nfsmount_start(struct nfsmount_info *mi)
e237fe4
 {
e237fe4
 	if (!nfs_validate_options(mi))
e237fe4
 		return EX_FAIL;
e237fe4
 
e237fe4
-	if (po_rightmost(mi->options, "bg", "fg") == PO_KEY1_RIGHTMOST)
e237fe4
+	if (po_rightmost(mi->options, nfs_background_opttbl) == 1)
e237fe4
 		return nfsmount_bg(mi);
e237fe4
 	else
e237fe4
 		return nfsmount_fg(mi);
e237fe4
e237fe4
text-based mount command: Function to stuff "struct pmap" from mount options
e237fe4
e237fe4
Both the text-based mount.nfs command and the umount.nfs command need
e237fe4
to fill in a pmap structure based on string mount options.  Introduce
e237fe4
a shared function that can do this.
e237fe4
e237fe4
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
e237fe4
---
e237fe4
e237fe4
 utils/mount/network.c |  214 +++++++++++++++++++++++++++++++++++++++++++++++++
e237fe4
 utils/mount/network.h |    5 +
e237fe4
 2 files changed, 219 insertions(+), 0 deletions(-)
e237fe4
e237fe4
diff --git a/utils/mount/network.c b/utils/mount/network.c
e237fe4
index d262e94..91a005c 100644
e237fe4
--- a/utils/mount/network.c
e237fe4
+++ b/utils/mount/network.c
e237fe4
@@ -48,6 +48,7 @@
e237fe4
 #include "nfs_mount.h"
e237fe4
 #include "mount_constants.h"
e237fe4
 #include "nfsrpc.h"
e237fe4
+#include "parse_opt.h"
e237fe4
 #include "network.h"
e237fe4
 
e237fe4
 #define PMAP_TIMEOUT	(10)
e237fe4
@@ -67,6 +68,33 @@ static const char *nfs_ns_pgmtbl[] = {
e237fe4
 	NULL,
e237fe4
 };
e237fe4
 
e237fe4
+static const char *nfs_mnt_pgmtbl[] = {
e237fe4
+	"mount",
e237fe4
+	"mountd",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
+static const char *nfs_nfs_pgmtbl[] = {
e237fe4
+	"nfs",
e237fe4
+	"nfsprog",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
+static const char *nfs_transport_opttbl[] = {
e237fe4
+	"udp",
e237fe4
+	"tcp",
e237fe4
+	"proto",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
+static const char *nfs_version_opttbl[] = {
e237fe4
+	"v2",
e237fe4
+	"v3",
e237fe4
+	"vers",
e237fe4
+	"nfsvers",
e237fe4
+	NULL,
e237fe4
+};
e237fe4
+
e237fe4
 static const unsigned long nfs_to_mnt[] = {
e237fe4
 	0,
e237fe4
 	0,
e237fe4
@@ -1111,3 +1139,189 @@ out_failed:
e237fe4
 	return 0;
e237fe4
 
e237fe4
 }
e237fe4
+
e237fe4
+/*
e237fe4
+ * "nfsprog" is only supported by the legacy mount command.  The
e237fe4
+ * kernel mount client does not support this option.
e237fe4
+ *
e237fe4
+ * Returns the value set by the nfsprog= option, the value of
e237fe4
+ * the RPC NFS program specified in /etc/rpc, or a baked-in
e237fe4
+ * default program number, if all fails.
e237fe4
+ */
e237fe4
+static rpcprog_t nfs_nfs_program(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	if (po_get_numeric(options, "nfsprog", &tmp) == PO_FOUND)
e237fe4
+		if (tmp >= 0)
e237fe4
+			return tmp;
e237fe4
+	return nfs_getrpcbyname(NFSPROG, nfs_nfs_pgmtbl);
e237fe4
+}
e237fe4
+
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the RPC version number specified by the given mount
e237fe4
+ * options for the NFS service, or zero if all fails.
e237fe4
+ */
e237fe4
+static rpcvers_t nfs_nfs_version(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	switch (po_rightmost(options, nfs_version_opttbl)) {
e237fe4
+	case 1:	/* v2 */
e237fe4
+		return 2;
e237fe4
+	case 2: /* v3 */
e237fe4
+		return 3;
e237fe4
+	case 3:	/* vers */
e237fe4
+		if (po_get_numeric(options, "vers", &tmp) == PO_FOUND)
e237fe4
+			if (tmp >= 2 && tmp <= 3)
e237fe4
+				return tmp;
e237fe4
+		break;
e237fe4
+	case 4: /* nfsvers */
e237fe4
+		if (po_get_numeric(options, "nfsvers", &tmp) == PO_FOUND)
e237fe4
+			if (tmp >= 2 && tmp <= 3)
e237fe4
+				return tmp;
e237fe4
+		break;
e237fe4
+	}
e237fe4
+
e237fe4
+	return 0;
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the NFS transport protocol specified by the given mount options
e237fe4
+ *
e237fe4
+ * Returns the IPPROTO_ value specified by the given mount options, or
e237fe4
+ * IPPROTO_UDP if all fails.
e237fe4
+ */
e237fe4
+static unsigned short nfs_nfs_protocol(struct mount_options *options)
e237fe4
+{
e237fe4
+	char *option;
e237fe4
+
e237fe4
+	switch (po_rightmost(options, nfs_transport_opttbl)) {
e237fe4
+	case 1:	/* udp */
e237fe4
+		return IPPROTO_UDP;
e237fe4
+	case 2: /* tcp */
e237fe4
+		return IPPROTO_TCP;
e237fe4
+	case 3: /* proto */
e237fe4
+		option = po_get(options, "proto");
e237fe4
+		if (option) {
e237fe4
+			if (strcmp(option, "tcp") == 0)
e237fe4
+				return IPPROTO_TCP;
e237fe4
+			if (strcmp(option, "udp") == 0)
e237fe4
+				return IPPROTO_UDP;
e237fe4
+		}
e237fe4
+	}
e237fe4
+	return IPPROTO_UDP;
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the NFS server's port number specified by the given
e237fe4
+ * mount options, or zero if all fails.  Zero results in a portmap
e237fe4
+ * query to discover the server's mountd service port.
e237fe4
+ *
e237fe4
+ * port=0 will guarantee an rpcbind request precedes the first
e237fe4
+ * NFS RPC so the client can determine the server's port number.
e237fe4
+ */
e237fe4
+static unsigned short nfs_nfs_port(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	if (po_get_numeric(options, "port", &tmp) == PO_FOUND)
e237fe4
+		if (tmp >= 0 && tmp <= 65535)
e237fe4
+			return tmp;
e237fe4
+	return 0;
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * "mountprog" is only supported by the legacy mount command.  The
e237fe4
+ * kernel mount client does not support this option.
e237fe4
+ *
e237fe4
+ * Returns the value set by the mountprog= option, the value of
e237fe4
+ * the RPC mount program specified in /etc/rpc, or a baked-in
e237fe4
+ * default program number, if all fails.
e237fe4
+ */
e237fe4
+static rpcprog_t nfs_mount_program(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	if (po_get_numeric(options, "mountprog", &tmp) == PO_FOUND)
e237fe4
+		if (tmp >= 0)
e237fe4
+			return tmp;
e237fe4
+	return nfs_getrpcbyname(MOUNTPROG, nfs_mnt_pgmtbl);
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the RPC version number specified by the given mount options,
e237fe4
+ * or the version "3" if all fails.
e237fe4
+ */
e237fe4
+static rpcvers_t nfs_mount_version(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	if (po_get_numeric(options, "mountvers", &tmp) == PO_FOUND)
e237fe4
+		if (tmp >= 1 && tmp <= 4)
e237fe4
+			return tmp;
e237fe4
+
e237fe4
+	return nfsvers_to_mnt(nfs_nfs_version(options));
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the transport protocol to use for the mount service
e237fe4
+ *
e237fe4
+ * Returns the IPPROTO_ value specified by the mountproto option, or
e237fe4
+ * if that doesn't exist, the IPPROTO_ value specified for NFS
e237fe4
+ * itself.
e237fe4
+ */
e237fe4
+static unsigned short nfs_mount_protocol(struct mount_options *options)
e237fe4
+{
e237fe4
+	char *option;
e237fe4
+
e237fe4
+	option = po_get(options, "mountproto");
e237fe4
+	if (option) {
e237fe4
+		if (strcmp(option, "tcp") == 0)
e237fe4
+			return IPPROTO_TCP;
e237fe4
+		if (strcmp(option, "udp") == 0)
e237fe4
+			return IPPROTO_UDP;
e237fe4
+	}
e237fe4
+
e237fe4
+	return nfs_nfs_version(options);
e237fe4
+}
e237fe4
+
e237fe4
+/*
e237fe4
+ * Returns the mountd server's port number specified by the given
e237fe4
+ * mount options, or zero if all fails.  Zero results in a portmap
e237fe4
+ * query to discover the server's mountd service port.
e237fe4
+ *
e237fe4
+ * port=0 will guarantee an rpcbind request precedes the mount
e237fe4
+ * RPC so the client can determine the server's port number.
e237fe4
+ */
e237fe4
+static unsigned short nfs_mount_port(struct mount_options *options)
e237fe4
+{
e237fe4
+	long tmp;
e237fe4
+
e237fe4
+	if (po_get_numeric(options, "mountport", &tmp) == PO_FOUND)
e237fe4
+		if (tmp >= 0 && tmp <= 65535)
e237fe4
+			return tmp;
e237fe4
+	return 0;
e237fe4
+}
e237fe4
+
e237fe4
+/**
e237fe4
+ * nfs_options2pmap - set up pmap structs based on mount options
e237fe4
+ * @options: pointer to mount options
e237fe4
+ * @nfs_pmap: OUT: pointer to pmap arguments for NFS server
e237fe4
+ * @mnt_pmap: OUT: pointer to pmap arguments for mountd server
e237fe4
+ *
e237fe4
+ */
e237fe4
+void nfs_options2pmap(struct mount_options *options,
e237fe4
+		      struct pmap *nfs_pmap, struct pmap *mnt_pmap)
e237fe4
+{
e237fe4
+	nfs_pmap->pm_prog = nfs_nfs_program(options);
e237fe4
+	nfs_pmap->pm_vers = nfs_nfs_version(options);
e237fe4
+	nfs_pmap->pm_prot = nfs_nfs_protocol(options);
e237fe4
+	nfs_pmap->pm_port = nfs_nfs_port(options);
e237fe4
+
e237fe4
+	mnt_pmap->pm_prog = nfs_mount_program(options);
e237fe4
+	mnt_pmap->pm_vers = nfs_mount_version(options);
e237fe4
+	mnt_pmap->pm_prot = nfs_mount_protocol(options);
e237fe4
+	mnt_pmap->pm_port = nfs_mount_port(options);
e237fe4
+}
e237fe4
diff --git a/utils/mount/network.h b/utils/mount/network.h
e237fe4
index 075093d..25060ab 100644
e237fe4
--- a/utils/mount/network.h
e237fe4
+++ b/utils/mount/network.h
e237fe4
@@ -57,6 +57,11 @@ int clnt_ping(struct sockaddr_in *, const unsigned long,
e237fe4
 		const unsigned long, const unsigned int,
e237fe4
 		struct sockaddr_in *);
e237fe4
 
e237fe4
+struct mount_options;
e237fe4
+
e237fe4
+void nfs_options2pmap(struct mount_options *,
e237fe4
+		      struct pmap *, struct pmap *);
e237fe4
+
e237fe4
 int start_statd(void);
e237fe4
 
e237fe4
 unsigned long nfsvers_to_mnt(const unsigned long);
e237fe4
e237fe4
text-based mount options: Use new pmap stuffer when	rewriting mount options
e237fe4
e237fe4
all nfs_options2pmap() in nfs_rewrite_mount_options() instead of
e237fe4
open-coding the logic to convert mount options to a pmap struct.
e237fe4
The new nfs_options2pmap() function is more careful about avoiding
e237fe4
invalid mount option values, and handles multiply-specified transport
e237fe4
protocol options correctly.
e237fe4
e237fe4
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
e237fe4
---
e237fe4
e237fe4
 utils/mount/stropts.c |   68 ++++---------------------------------------------
e237fe4
 1 files changed, 5 insertions(+), 63 deletions(-)
e237fe4
e237fe4
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
e237fe4
index bd127ab..99be0f3 100644
e237fe4
--- a/utils/mount/stropts.c
e237fe4
+++ b/utils/mount/stropts.c
e237fe4
@@ -322,19 +322,12 @@ static int nfs_is_permanent_error(int error)
e237fe4
  * Returns a new group of mount options if successful; otherwise
e237fe4
  * NULL is returned if some failure occurred.
e237fe4
  */
e237fe4
-static const char *nfs_transport_opttbl[] = {
e237fe4
-	"udp",
e237fe4
-	"tcp",
e237fe4
-	NULL,
e237fe4
-};
e237fe4
-
e237fe4
 static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 {
e237fe4
 	struct mount_options *options;
e237fe4
 	char *option, new_option[64];
e237fe4
 	clnt_addr_t mnt_server = { };
e237fe4
 	clnt_addr_t nfs_server = { };
e237fe4
-	int p;
e237fe4
 
e237fe4
 	options = po_split(str);
e237fe4
 	if (!options) {
e237fe4
@@ -360,64 +353,13 @@ static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 		memcpy(&mnt_server.saddr, &nfs_server.saddr,
e237fe4
 				sizeof(mnt_server.saddr));
e237fe4
 
e237fe4
-	option = po_get(options, "mountport");
e237fe4
-	if (option)
e237fe4
-		mnt_server.pmap.pm_port = atoi(option);
e237fe4
-	mnt_server.pmap.pm_prog = MOUNTPROG;
e237fe4
-	option = po_get(options, "mountvers");
e237fe4
-	if (option)
e237fe4
-		mnt_server.pmap.pm_vers = atoi(option);
e237fe4
-	option = po_get(options, "mountproto");
e237fe4
-	if (option) {
e237fe4
-		if (strcmp(option, "tcp") == 0) {
e237fe4
-			mnt_server.pmap.pm_prot = IPPROTO_TCP;
e237fe4
-			po_remove_all(options, "mountproto");
e237fe4
-		}
e237fe4
-		if (strcmp(option, "udp") == 0) {
e237fe4
-			mnt_server.pmap.pm_prot = IPPROTO_UDP;
e237fe4
-			po_remove_all(options, "mountproto");
e237fe4
-		}
e237fe4
-	}
e237fe4
+	nfs_options2pmap(options, &nfs_server.pmap, &mnt_server.pmap);
e237fe4
 
e237fe4
-	option = po_get(options, "port");
e237fe4
-	if (option) {
e237fe4
-		nfs_server.pmap.pm_port = atoi(option);
e237fe4
-		po_remove_all(options, "port");
e237fe4
-	}
e237fe4
+	/* The kernel NFS client doesn't support changing the RPC program
e237fe4
+	 * number for these services, so reset these fields before probing
e237fe4
+	 * the server's ports.  */
e237fe4
 	nfs_server.pmap.pm_prog = NFS_PROGRAM;
e237fe4
-
e237fe4
-	option = po_get(options, "nfsvers");
e237fe4
-	if (option) {
e237fe4
-		nfs_server.pmap.pm_vers = atoi(option);
e237fe4
-		po_remove_all(options, "nfsvers");
e237fe4
-	}
e237fe4
-	option = po_get(options, "vers");
e237fe4
-	if (option) {
e237fe4
-		nfs_server.pmap.pm_vers = atoi(option);
e237fe4
-		po_remove_all(options, "vers");
e237fe4
-	}
e237fe4
-	option = po_get(options, "proto");
e237fe4
-	if (option) {
e237fe4
-		if (strcmp(option, "tcp") == 0) {
e237fe4
-			nfs_server.pmap.pm_prot = IPPROTO_TCP;
e237fe4
-			po_remove_all(options, "proto");
e237fe4
-		}
e237fe4
-		if (strcmp(option, "udp") == 0) {
e237fe4
-			nfs_server.pmap.pm_prot = IPPROTO_UDP;
e237fe4
-			po_remove_all(options, "proto");
e237fe4
-		}
e237fe4
-	}
e237fe4
-	p = po_rightmost(options, nfs_transport_opttbl);
e237fe4
-	switch (p) {
e237fe4
-	case 1:
e237fe4
-		nfs_server.pmap.pm_prot = IPPROTO_UDP;
e237fe4
-		break;
e237fe4
-	case 2:
e237fe4
-		nfs_server.pmap.pm_prot = IPPROTO_TCP;
e237fe4
-		break;
e237fe4
-	}
e237fe4
-	po_remove_all(options, "tcp");
e237fe4
-	po_remove_all(options, "udp");
e237fe4
+	mnt_server.pmap.pm_prog = MOUNTPROG;
e237fe4
 
e237fe4
 	if (!probe_bothports(&mnt_server, &nfs_server)) {
e237fe4
 		errno = ESPIPE;
e237fe4
e237fe4
text-based mount command: fix mount option rewriting logic
e237fe4
e237fe4
Fix a bunch of corner cases in the text-based mount option rewriting logic.
e237fe4
e237fe4
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
e237fe4
---
e237fe4
e237fe4
 utils/mount/stropts.c |  113 ++++++++++++++++++++++++++++++++++---------------
e237fe4
 1 files changed, 79 insertions(+), 34 deletions(-)
e237fe4
e237fe4
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
e237fe4
index 99be0f3..319be71 100644
e237fe4
--- a/utils/mount/stropts.c
e237fe4
+++ b/utils/mount/stropts.c
e237fe4
@@ -309,6 +309,81 @@ static int nfs_is_permanent_error(int error)
e237fe4
 	}
e237fe4
 }
e237fe4
 
e237fe4
+static int nfs_construct_new_options(struct mount_options *options,
e237fe4
+				     struct pmap *nfs_pmap,
e237fe4
+				     struct pmap *mnt_pmap)
e237fe4
+{
e237fe4
+	char new_option[64];
e237fe4
+
e237fe4
+	po_remove_all(options, "nfsprog");
e237fe4
+	po_remove_all(options, "mountprog");
e237fe4
+
e237fe4
+	po_remove_all(options, "v2");
e237fe4
+	po_remove_all(options, "v3");
e237fe4
+	po_remove_all(options, "vers");
e237fe4
+	po_remove_all(options, "nfsvers");
e237fe4
+	snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+		 "vers=%lu", nfs_pmap->pm_vers);
e237fe4
+	if (po_append(options, new_option) == PO_FAILED)
e237fe4
+		return 0;
e237fe4
+
e237fe4
+	po_remove_all(options, "proto");
e237fe4
+	po_remove_all(options, "udp");
e237fe4
+	po_remove_all(options, "tcp");
e237fe4
+	switch (nfs_pmap->pm_prot) {
e237fe4
+	case IPPROTO_TCP:
e237fe4
+		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+			 "proto=tcp");
e237fe4
+		if (po_append(options, new_option) == PO_FAILED)
e237fe4
+			return 0;
e237fe4
+		break;
e237fe4
+	case IPPROTO_UDP:
e237fe4
+		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+			 "proto=udp");
e237fe4
+		if (po_append(options, new_option) == PO_FAILED)
e237fe4
+			return 0;
e237fe4
+		break;
e237fe4
+	}
e237fe4
+
e237fe4
+	po_remove_all(options, "port");
e237fe4
+	if (nfs_pmap->pm_port != NFS_PORT) {
e237fe4
+		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+			 "port=%lu", nfs_pmap->pm_port);
e237fe4
+		if (po_append(options, new_option) == PO_FAILED)
e237fe4
+			return 0;
e237fe4
+	}
e237fe4
+
e237fe4
+	po_remove_all(options, "mountvers");
e237fe4
+	snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+		 "mountvers=%lu", mnt_pmap->pm_vers);
e237fe4
+	if (po_append(options, new_option) == PO_FAILED)
e237fe4
+		return 0;
e237fe4
+
e237fe4
+	po_remove_all(options, "mountproto");
e237fe4
+	switch (mnt_pmap->pm_prot) {
e237fe4
+	case IPPROTO_TCP:
e237fe4
+		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+			 "mountproto=tcp");
e237fe4
+		if (po_append(options, new_option) == PO_FAILED)
e237fe4
+			return 0;
e237fe4
+		break;
e237fe4
+	case IPPROTO_UDP:
e237fe4
+		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+			 "mountproto=udp");
e237fe4
+		if (po_append(options, new_option) == PO_FAILED)
e237fe4
+			return 0;
e237fe4
+		break;
e237fe4
+	}
e237fe4
+
e237fe4
+	po_remove_all(options, "mountport");
e237fe4
+	snprintf(new_option, sizeof(new_option) - 1,
e237fe4
+		 "mountport=%lu", mnt_pmap->pm_port);
e237fe4
+	if (po_append(options, new_option) == PO_FAILED)
e237fe4
+		return 0;
e237fe4
+
e237fe4
+	return 1;
e237fe4
+}
e237fe4
+
e237fe4
 /*
e237fe4
  * Reconstruct the mount option string based on a portmapper probe
e237fe4
  * of the server.  Returns one if the server's portmapper returned
e237fe4
@@ -325,7 +400,7 @@ static int nfs_is_permanent_error(int error)
e237fe4
 static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 {
e237fe4
 	struct mount_options *options;
e237fe4
-	char *option, new_option[64];
e237fe4
+	char *option;
e237fe4
 	clnt_addr_t mnt_server = { };
e237fe4
 	clnt_addr_t nfs_server = { };
e237fe4
 
e237fe4
@@ -366,42 +441,12 @@ static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 		goto err;
e237fe4
 	}
e237fe4
 
e237fe4
-	snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-		 "nfsvers=%lu", nfs_server.pmap.pm_vers);
e237fe4
-	if (po_append(options, new_option) == PO_FAILED)
e237fe4
+	if (!nfs_construct_new_options(options,
e237fe4
+					&nfs_server.pmap, &mnt_server.pmap)) {
e237fe4
+		errno = EINVAL;
e237fe4
 		goto err;
e237fe4
-
e237fe4
-	if (nfs_server.pmap.pm_prot == IPPROTO_TCP)
e237fe4
-		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-			 "proto=tcp");
e237fe4
-	else
e237fe4
-		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-			 "proto=udp");
e237fe4
-	if (po_append(options, new_option) == PO_FAILED)
e237fe4
-		goto err;
e237fe4
-
e237fe4
-	if (nfs_server.pmap.pm_port != NFS_PORT) {
e237fe4
-		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-			 "port=%lu", nfs_server.pmap.pm_port);
e237fe4
-		if (po_append(options, new_option) == PO_FAILED)
e237fe4
-			goto err;
e237fe4
-
e237fe4
 	}
e237fe4
 
e237fe4
-	if (mnt_server.pmap.pm_prot == IPPROTO_TCP)
e237fe4
-		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-			 "mountproto=tcp");
e237fe4
-	else
e237fe4
-		snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-			 "mountproto=udp");
e237fe4
-	if (po_append(options, new_option) == PO_FAILED)
e237fe4
-		goto err;
e237fe4
-
e237fe4
-	snprintf(new_option, sizeof(new_option) - 1,
e237fe4
-		 "mountport=%lu", mnt_server.pmap.pm_port);
e237fe4
-	if (po_append(options, new_option) == PO_FAILED)
e237fe4
-		goto err;
e237fe4
-
e237fe4
 	errno = 0;
e237fe4
 	return options;
e237fe4
 
e237fe4
e237fe4
text-based mount command: support AF_INET6 in	rewrite_mount_options()
e237fe4
e237fe4
Now that we have an AF_INET6-capable probe_bothports(), we can support
e237fe4
AF_INET6 when rewriting text-based NFS mount options.  This should be
e237fe4
adequate to support NFS transport protocol and version negotiation with
e237fe4
AF_INET6 NFS servers.
e237fe4
e237fe4
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
e237fe4
---
e237fe4
e237fe4
 utils/mount/stropts.c |   74 ++++++++++++++++++++++++++++++++-----------------
e237fe4
 1 files changed, 49 insertions(+), 25 deletions(-)
e237fe4
e237fe4
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
e237fe4
index 319be71..6d44bb7 100644
e237fe4
--- a/utils/mount/stropts.c
e237fe4
+++ b/utils/mount/stropts.c
e237fe4
@@ -309,6 +309,37 @@ static int nfs_is_permanent_error(int error)
e237fe4
 	}
e237fe4
 }
e237fe4
 
e237fe4
+/*
e237fe4
+ * Get NFS/mnt server addresses from mount options
e237fe4
+ *
e237fe4
+ * Returns 1 and fills in @nfs_saddr, @nfs_salen, @mnt_saddr, and @mnt_salen
e237fe4
+ * if all goes well; otherwise zero.
e237fe4
+ */
e237fe4
+static int nfs_extract_server_addresses(struct mount_options *options,
e237fe4
+					struct sockaddr *nfs_saddr,
e237fe4
+					socklen_t *nfs_salen,
e237fe4
+					struct sockaddr *mnt_saddr,
e237fe4
+					socklen_t *mnt_salen)
e237fe4
+{
e237fe4
+	char *option;
e237fe4
+
e237fe4
+	option = po_get(options, "addr");
e237fe4
+	if (option == NULL)
e237fe4
+		return 0;
e237fe4
+	if (!nfs_string_to_sockaddr(option, strlen(option),
e237fe4
+						nfs_saddr, nfs_salen))
e237fe4
+		return 0;
e237fe4
+
e237fe4
+	option = po_get(options, "mountaddr");
e237fe4
+	if (option == NULL)
e237fe4
+		memcpy(mnt_saddr, nfs_saddr, *nfs_salen);
e237fe4
+	else if (!nfs_string_to_sockaddr(option, strlen(option),
e237fe4
+						mnt_saddr, mnt_salen))
e237fe4
+		return 0;
e237fe4
+
e237fe4
+	return 1;
e237fe4
+}
e237fe4
+
e237fe4
 static int nfs_construct_new_options(struct mount_options *options,
e237fe4
 				     struct pmap *nfs_pmap,
e237fe4
 				     struct pmap *mnt_pmap)
e237fe4
@@ -400,9 +431,14 @@ static int nfs_construct_new_options(struct mount_options *options,
e237fe4
 static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 {
e237fe4
 	struct mount_options *options;
e237fe4
-	char *option;
e237fe4
-	clnt_addr_t mnt_server = { };
e237fe4
-	clnt_addr_t nfs_server = { };
e237fe4
+	struct sockaddr_storage nfs_address;
e237fe4
+	struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address;
e237fe4
+	socklen_t nfs_salen;
e237fe4
+	struct pmap nfs_pmap;
e237fe4
+	struct sockaddr_storage mnt_address;
e237fe4
+	struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address;
e237fe4
+	socklen_t mnt_salen;
e237fe4
+	struct pmap mnt_pmap;
e237fe4
 
e237fe4
 	options = po_split(str);
e237fe4
 	if (!options) {
e237fe4
@@ -410,39 +446,27 @@ static struct mount_options *nfs_rewrite_mount_options(char *str)
e237fe4
 		return NULL;
e237fe4
 	}
e237fe4
 
e237fe4
-	errno = EINVAL;
e237fe4
-	option = po_get(options, "addr");
e237fe4
-	if (option) {
e237fe4
-		nfs_server.saddr.sin_family = AF_INET;
e237fe4
-		if (!inet_aton((const char *)option, &nfs_server.saddr.sin_addr))
e237fe4
-			goto err;
e237fe4
-	} else
e237fe4
+	if (!nfs_extract_server_addresses(options, nfs_saddr, &nfs_salen,
e237fe4
+						mnt_saddr, &mnt_salen)) {
e237fe4
+		errno = EINVAL;
e237fe4
 		goto err;
e237fe4
+	}
e237fe4
 
e237fe4
-	option = po_get(options, "mountaddr");
e237fe4
-	if (option) {
e237fe4
-		mnt_server.saddr.sin_family = AF_INET;
e237fe4
-		if (!inet_aton((const char *)option, &mnt_server.saddr.sin_addr))
e237fe4
-			goto err;
e237fe4
-	} else
e237fe4
-		memcpy(&mnt_server.saddr, &nfs_server.saddr,
e237fe4
-				sizeof(mnt_server.saddr));
e237fe4
-
e237fe4
-	nfs_options2pmap(options, &nfs_server.pmap, &mnt_server.pmap);
e237fe4
+	nfs_options2pmap(options, &nfs_pmap, &mnt_pmap);
e237fe4
 
e237fe4
 	/* The kernel NFS client doesn't support changing the RPC program
e237fe4
 	 * number for these services, so reset these fields before probing
e237fe4
 	 * the server's ports.  */
e237fe4
-	nfs_server.pmap.pm_prog = NFS_PROGRAM;
e237fe4
-	mnt_server.pmap.pm_prog = MOUNTPROG;
e237fe4
+	nfs_pmap.pm_prog = NFS_PROGRAM;
e237fe4
+	mnt_pmap.pm_prog = MOUNTPROG;
e237fe4
 
e237fe4
-	if (!probe_bothports(&mnt_server, &nfs_server)) {
e237fe4
+	if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap,
e237fe4
+				 nfs_saddr, nfs_salen, &nfs_pmap)) {
e237fe4
 		errno = ESPIPE;
e237fe4
 		goto err;
e237fe4
 	}
e237fe4
 
e237fe4
-	if (!nfs_construct_new_options(options,
e237fe4
-					&nfs_server.pmap, &mnt_server.pmap)) {
e237fe4
+	if (!nfs_construct_new_options(options, &nfs_pmap, &mnt_pmap)) {
e237fe4
 		errno = EINVAL;
e237fe4
 		goto err;
e237fe4
 	}
e237fe4