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