+/*
+ * Obtain a retry timeout value based on the value of the "retry=" option.
+ *
+ * Returns a time_t timeout timestamp, in seconds.
+ */
+static time_t nfs_parse_retry_option(struct mount_options *options,
+ unsigned int timeout_minutes)
+{
+ long tmp;
+
+ switch (po_get_numeric(options, "retry", &tmp)) {
+ case PO_NOT_FOUND:
+ break;
+ case PO_FOUND:
+ if (tmp >= 0) {
+ timeout_minutes = tmp;
+ break;
+ }
+ case PO_BAD_VALUE:
+ if (verbose)
+ nfs_error(_("%s: invalid retry timeout was specified; "
+ "using default timeout"), progname);
+ break;
+ }
+
+ return time(NULL) + (time_t)(timeout_minutes * 60);
+}
+
+/*
+ * Convert the passed-in sockaddr-style address to presentation
+ * format, then append an option of the form "keyword=address".
+ *
+ * Returns 1 if the option was appended successfully; otherwise zero.
+ */
+static int nfs_append_generic_address_option(const struct sockaddr *sap,
+ const socklen_t salen,
+ const char *keyword,
+ struct mount_options *options)
+{
+ char address[NI_MAXHOST];
+ char new_option[512];
+ int len;
+
+ if (!nfs_present_sockaddr(sap, salen, address, sizeof(address)))
+ goto out_err;
+
+ len = snprintf(new_option, sizeof(new_option), "%s=%s",
+ keyword, address);
+ if (len < 0 || (size_t)len >= sizeof(new_option))
+ goto out_err;
+
+ if (po_append(options, new_option) != PO_SUCCEEDED)
+ goto out_err;
+
+ return 1;
+
+out_err:
+ nfs_error(_("%s: failed to construct %s option"), progname, keyword);
+ return 0;
+}
+
+/*
+ * Append the 'addr=' option to the options string to pass a resolved
+ * server address to the kernel. After a successful mount, this address
+ * is also added to /etc/mtab for use when unmounting.
+ *
+ * If 'addr=' is already present, we strip it out. This prevents users
+ * from setting a bogus 'addr=' option themselves, and also allows bg
+ * retries to recompute the server's address, in case it has changed.
+ *
+ * Returns 1 if 'addr=' option appended successfully;
+ * otherwise zero.
+ */
+static int nfs_append_addr_option(const struct sockaddr *sap,
+ socklen_t salen,
+ struct mount_options *options)
+{
+ po_remove_all(options, "addr");
+ return nfs_append_generic_address_option(sap, salen, "addr", options);
+}
+
+/*
+ * Called to discover our address and append an appropriate 'clientaddr='
+ * option to the options string.
+ *
+ * Returns 1 if 'clientaddr=' option created successfully or if
+ * 'clientaddr=' option is already present; otherwise zero.
+ */
+static int nfs_append_clientaddr_option(const struct sockaddr *sap,
+ socklen_t salen,
+ struct mount_options *options)
+{
+ union nfs_sockaddr address;
+ struct sockaddr *my_addr = &address.sa;
+ socklen_t my_len = sizeof(address);
+
+ if (po_contains(options, "clientaddr") == PO_FOUND)
+ return 1;
+
+ nfs_callback_address(sap, salen, my_addr, &my_len);
+
+ return nfs_append_generic_address_option(my_addr, my_len,
+ "clientaddr", options);
+}
+
+/*
+ * Determine whether to append a 'mountaddr=' option. The option is needed if:
+ *
+ * 1. "mounthost=" was specified, or
+ * 2. The address families for proto= and mountproto= are different.
+ */
+static int nfs_fix_mounthost_option(struct mount_options *options,
+ const char *nfs_hostname)
+{
+ union nfs_sockaddr address;
+ struct sockaddr *sap = &address.sa;
+ socklen_t salen = sizeof(address);
+ sa_family_t nfs_family, mnt_family;
+ char *mounthost;
+
+ if (!nfs_nfs_proto_family(options, &nfs_family))
+ return 0;
+ if (!nfs_mount_proto_family(options, &mnt_family))
+ return 0;
+
+ mounthost = po_get(options, "mounthost");
+ if (mounthost == NULL) {
+ if (nfs_family == mnt_family)
+ return 1;
+ mounthost = (char *)nfs_hostname;