+ option = po_get(options, "addr");
+ if (option == NULL)
+ return 0;
+ if (!nfs_string_to_sockaddr(option, nfs_saddr, nfs_salen))
+ return 0;
+
+ option = po_get(options, "mountaddr");
+ if (option == NULL) {
+ memcpy(mnt_saddr, nfs_saddr, *nfs_salen);
+ *mnt_salen = *nfs_salen;
+ } else if (!nfs_string_to_sockaddr(option, mnt_saddr, mnt_salen))
+ return 0;
+
+ return 1;
+}
+
+static int nfs_construct_new_options(struct mount_options *options,
+ struct sockaddr *nfs_saddr,
+ struct pmap *nfs_pmap,
+ struct sockaddr *mnt_saddr,
+ struct pmap *mnt_pmap)
+{
+ char new_option[64];
+ char *netid;
+
+ 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");
+ netid = nfs_get_netid(nfs_saddr->sa_family, nfs_pmap->pm_prot);
+ if (netid == NULL)
+ return 0;
+ snprintf(new_option, sizeof(new_option) - 1,
+ "proto=%s", netid);
+ free(netid);
+ if (po_append(options, new_option) == PO_FAILED)
+ return 0;
+
+ if(po_remove_all(options, "port") == PO_FOUND ||
+ 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");
+ netid = nfs_get_netid(mnt_saddr->sa_family, mnt_pmap->pm_prot);
+ if (netid == NULL)
+ return 0;
+ snprintf(new_option, sizeof(new_option) - 1,
+ "mountproto=%s", netid);
+ free(netid);
+ if (po_append(options, new_option) == PO_FAILED)
+ return 0;
+
+ 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
+ * something we can use, otherwise zero.
+ *
+ * To handle version and transport protocol fallback properly, we
+ * need to parse some of the mount options in order to set up a
+ * portmap probe. Mount options that nfs_rewrite_pmap_mount_options()
+ * doesn't recognize are left alone.
+ *
+ * Returns TRUE if rewriting was successful; otherwise
+ * FALSE is returned if some failure occurred.
+ */
+static int
+nfs_rewrite_pmap_mount_options(struct mount_options *options)
+{
+ union nfs_sockaddr nfs_address;
+ struct sockaddr *nfs_saddr = &nfs_address.sa;
+ socklen_t nfs_salen = sizeof(nfs_address);
+ struct pmap nfs_pmap;
+ union nfs_sockaddr mnt_address;
+ struct sockaddr *mnt_saddr = &mnt_address.sa;
+ socklen_t mnt_salen = sizeof(mnt_address);
+ unsigned long protocol;
+ struct pmap mnt_pmap;
+
+ /*
+ * Version and transport negotiation is not required
+ * and does not work for RDMA mounts.
+ */
+ if (!nfs_nfs_protocol(options, &protocol)) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (protocol == NFSPROTO_RDMA)