#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 "network.h"
#include "parse_opt.h"
#include "version.h"
+#include "parse_dev.h"
#ifdef HAVE_RPCSVC_NFS_PROT_H
#include <rpcsvc/nfs_prot.h>
int flags, /* MS_ flags */
fake, /* actually do the mount? */
child; /* forked bg child? */
-};
-
-static int nfs_parse_devname(struct nfsmount_info *mi)
-{
- int ret = 0;
- char *dev, *pathname, *s;
-
- dev = xstrdup(mi->spec);
-
- if (!(pathname = strchr(dev, ':'))) {
- nfs_error(_("%s: remote share not in 'host:dir' format"),
- progname);
- goto out;
- }
- *pathname = '\0';
- pathname++;
-
- /*
- * We don't need a copy of the pathname, but let's
- * sanity check it anyway.
- */
- if (strlen(pathname) > NFS_MAXPATHNAME) {
- nfs_error(_("%s: export pathname is too long"),
- progname);
- goto out;
- }
-
- /*
- * Ignore all but first hostname in replicated mounts
- * until they can be fully supported. (mack@sgi.com)
- */
- if ((s = strchr(dev, ','))) {
- *s = '\0';
- nfs_error(_("%s: warning: multiple hostnames not supported"),
- progname);
- nfs_error(_("%s: ignoring hostnames that follow the first one"),
- progname);
- }
- mi->hostname = xstrdup(dev);
- if (strlen(mi->hostname) > NFS_MAXHOSTNAME) {
- nfs_error(_("%s: server hostname is too long"),
- progname);
- free(mi->hostname);
- mi->hostname = NULL;
- goto out;
- }
-
- ret = 1;
-out:
- free(dev);
- return ret;
-}
+ sa_family_t family; /* supported address family */
+};
static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
{
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);
}
/*
* Returns 1 if 'clientaddr=' option created successfully or if
* 'clientaddr=' option is already present; otherwise zero.
*/
-static int append_clientaddr_option(struct sockaddr_in *saddr,
- struct mount_options *options)
+static int nfs_append_clientaddr_option(const struct sockaddr *sap,
+ socklen_t salen,
+ struct mount_options *options)
{
- struct sockaddr_in my_addr;
- char new_option[32];
+ struct sockaddr_storage dummy;
+ struct sockaddr *my_addr = (struct sockaddr *)&dummy;
+ socklen_t my_len = sizeof(dummy);
- if (po_contains(options, "clientaddr") == PO_SUCCEEDED)
+ if (po_contains(options, "clientaddr") == PO_FOUND)
return 1;
- if (!get_client_address(saddr, &my_addr))
- return 0;
-
- snprintf(new_option, sizeof(new_option) - 1,
- "clientaddr=%s", inet_ntoa(my_addr.sin_addr));
+ nfs_callback_address(sap, salen, my_addr, &my_len);
- if (po_append(options, new_option) == PO_SUCCEEDED)
- return 1;
- return 0;
+ return nfs_append_generic_address_option(my_addr, my_len,
+ "clientaddr", options);
}
/*
* Resolve the 'mounthost=' hostname and append a new option using
- * the resulting IPv4 address.
+ * the resulting address.
*/
-static int fix_mounthost_option(struct mount_options *options)
+static int nfs_fix_mounthost_option(const sa_family_t family,
+ struct mount_options *options)
{
- struct sockaddr_in maddr;
- char *mounthost, new_option[32];
+ struct sockaddr_storage dummy;
+ struct sockaddr *sap = (struct sockaddr *)&dummy;
+ socklen_t salen = sizeof(dummy);
+ char *mounthost;
mounthost = po_get(options, "mounthost");
if (!mounthost)
return 1;
- if (!fill_ipv4_sockaddr(mounthost, &maddr))
+ if (!nfs_name_to_address(mounthost, family, sap, &salen)) {
+ nfs_error(_("%s: unable to determine mount server's address"),
+ progname);
return 0;
+ }
- snprintf(new_option, sizeof(new_option) - 1,
- "mountaddr=%s", inet_ntoa(maddr.sin_addr));
-
- if (po_append(options, new_option) == PO_SUCCEEDED)
- return 1;
- return 0;
+ return nfs_append_generic_address_option(sap, salen,
+ "mountaddr", options);
}
/*
*/
static int nfs_validate_options(struct nfsmount_info *mi)
{
- struct sockaddr_in saddr;
+ struct sockaddr_storage dummy;
+ struct sockaddr *sap = (struct sockaddr *)&dummy;
+ socklen_t salen = sizeof(dummy);
- if (!fill_ipv4_sockaddr(mi->hostname, &saddr))
+ if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL))
+ return 0;
+
+ if (!nfs_name_to_address(mi->hostname, mi->family, sap, &salen))
return 0;
if (strncmp(mi->type, "nfs4", 4) == 0) {
- if (!append_clientaddr_option(&saddr, mi->options))
+ if (!nfs_append_clientaddr_option(sap, salen, mi->options))
return 0;
} else {
- if (!fix_mounthost_option(mi->options))
+ if (!nfs_fix_mounthost_option(mi->family, mi->options))
return 0;
if (!mi->fake && !verify_lock_option(mi->options))
return 0;
if (!nfs_append_sloppy_option(mi->options))
return 0;
- if (!append_addr_option(&saddr, mi->options))
- return 0;
-
- return 1;
+ return nfs_append_addr_option(sap, salen, mi->options);
}
/*
.flags = flags,
.fake = fake,
.child = child,
+#ifdef IPV6_SUPPORTED
+ .family = AF_UNSPEC, /* either IPv4 or v6 */
+#else
+ .family = AF_INET, /* only IPv4 */
+#endif
};
int retval = EX_FAIL;
- if (!nfs_parse_devname(&mi))
- return retval;
-
mi.options = po_split(*extra_opts);
if (mi.options) {
retval = nfsmount_start(&mi);