]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/stropts.c
Traditionally the mount command has looked for a ":" to separate the
[nfs-utils.git] / utils / mount / stropts.c
index a9c0b504e400ae386289e546e8ca0e3a61b4e18d..c4f2326ce9162ef63d08c649be0f7091532ca37e 100644 (file)
@@ -49,6 +49,7 @@
 #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>
@@ -94,59 +95,9 @@ struct nfsmount_info {
        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)
 {
@@ -194,6 +145,37 @@ static time_t nfs_parse_retry_option(struct mount_options *options,
        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
@@ -206,19 +188,12 @@ static time_t nfs_parse_retry_option(struct mount_options *options,
  * 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);
 }
 
 /*
@@ -228,48 +203,47 @@ static int append_addr_option(struct sockaddr_in *saddr,
  * 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);
 }
 
 /*
@@ -309,16 +283,21 @@ static int nfs_append_sloppy_option(struct mount_options *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;
@@ -327,10 +306,7 @@ static int nfs_validate_options(struct nfsmount_info *mi)
        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);
 }
 
 /*
@@ -780,12 +756,14 @@ int nfsmount_string(const char *spec, const char *node, const char *type,
                .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);