#include <errno.h>
#include <netdb.h>
#include <time.h>
+
#include <sys/socket.h>
#include <sys/mount.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include "xcommon.h"
#include "mount.h"
#include "error.h"
#include "network.h"
#include "parse_opt.h"
+#include "version.h"
#ifdef HAVE_RPCSVC_NFS_PROT_H
#include <rpcsvc/nfs_prot.h>
extern int nfs_mount_data_version;
extern char *progname;
extern int verbose;
+extern int sloppy;
struct nfsmount_info {
const char *spec, /* server:/path */
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];
+
+ if (!nfs_present_sockaddr(sap, salen, address, sizeof(address)))
+ goto out_err;
+
+ if (snprintf(new_option, sizeof(new_option), "%s=%s",
+ keyword, address) >= 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
* Returns 1 if 'addr=' option appended successfully;
* otherwise zero.
*/
-static int append_addr_option(struct sockaddr_in *saddr,
- struct mount_options *options)
+static int nfs_append_addr_option(const struct sockaddr *sap,
+ socklen_t salen,
+ struct mount_options *options)
{
- char new_option[24];
-
po_remove_all(options, "addr");
-
- snprintf(new_option, sizeof(new_option) - 1,
- "addr=%s", inet_ntoa(saddr->sin_addr));
-
- if (po_append(options, new_option) == PO_SUCCEEDED)
- return 1;
- return 0;
+ return nfs_append_generic_address_option(sap, salen, "addr", options);
}
/*
return 1;
}
+static int nfs_append_sloppy_option(struct mount_options *options)
+{
+ if (!sloppy || linux_version_code() < MAKE_VERSION(2, 6, 27))
+ return 1;
+
+ if (po_append(options, "sloppy") == PO_FAILED)
+ return 0;
+ return 1;
+}
+
/*
* Set up mandatory NFS mount options.
*
return 0;
}
- if (!append_addr_option(&saddr, mi->options))
+ if (!nfs_append_sloppy_option(mi->options))
return 0;
- return 1;
+ return nfs_append_addr_option((struct sockaddr *)&saddr,
+ sizeof(saddr), mi->options);
}
/*
int p;
options = po_split(str);
- if (!options)
+ if (!options) {
+ errno = EFAULT;
return NULL;
+ }
+ errno = EINVAL;
option = po_get(options, "addr");
if (option) {
nfs_server.saddr.sin_family = AF_INET;
po_remove_all(options, "udp");
if (!probe_bothports(&mnt_server, &nfs_server)) {
- rpc_mount_errors("rpcbind", 0, 0);
+ errno = ESPIPE;
goto err;
}
}
+ errno = 0;
return options;
err:
char **extra_opts = mi->extra_opts;
retry_options = rewrite_mount_options(*extra_opts);
- if (!retry_options) {
- errno = EIO;
+ if (!retry_options)
return 0;
- }
if (po_join(retry_options, &retry_str) == PO_FAILED) {
po_destroy(retry_options);