X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=c5b92fc12f4f58633d5fd17b37acf68aa23e8b4e;hp=3a2a237931835eeea19ca311138079442221235b;hb=b58c5b62ac47f84bca17fc7999e30b0a43ccb92d;hpb=57af0cce3ed6f555bb40132d667e8b10d41855ca diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 3a2a237..c5b92fc 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -38,6 +38,7 @@ #include "xcommon.h" #include "mount.h" #include "nls.h" +#include "nfsrpc.h" #include "mount_constants.h" #include "stropts.h" #include "error.h" @@ -76,12 +77,18 @@ extern char *progname; extern int verbose; extern int sloppy; +union nfs_sockaddr { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; +}; + struct nfsmount_info { const char *spec, /* server:/path */ *node, /* mounted-on dir */ *type; /* "nfs" or "nfs4" */ char *hostname; /* server's hostname */ - struct sockaddr_storage address; /* server's address */ + union nfs_sockaddr address; socklen_t salen; /* size of server's address */ struct mount_options *options; /* parsed mount options */ @@ -204,9 +211,9 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, socklen_t salen, struct mount_options *options) { - struct sockaddr_storage dummy; - struct sockaddr *my_addr = (struct sockaddr *)&dummy; - socklen_t my_len = sizeof(dummy); + 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; @@ -223,9 +230,9 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, */ static int nfs_fix_mounthost_option(struct mount_options *options) { - struct sockaddr_storage dummy; - struct sockaddr *sap = (struct sockaddr *)&dummy; - socklen_t salen = sizeof(dummy); + union nfs_sockaddr address; + struct sockaddr *sap = &address.sa; + socklen_t salen = sizeof(address); char *mounthost; mounthost = po_get(options, "mounthost"); @@ -278,24 +285,11 @@ static int nfs_append_sloppy_option(struct mount_options *options) return 1; } -/* - * Set up mandatory non-version specific NFS mount options. - * - * Returns 1 if successful; otherwise zero. - */ -static int nfs_validate_options(struct nfsmount_info *mi) +static int nfs_set_version(struct nfsmount_info *mi) { - struct sockaddr *sap = (struct sockaddr *)&mi->address; - - if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) - return 0; - - mi->salen = sizeof(mi->address); - if (!nfs_name_to_address(mi->hostname, sap, &mi->salen)) - return 0; - if (!nfs_nfs_version(mi->options, &mi->version)) return 0; + if (strncmp(mi->type, "nfs4", 4) == 0) mi->version = 4; else { @@ -304,11 +298,45 @@ static int nfs_validate_options(struct nfsmount_info *mi) mi->version = 3; } + /* + * If we still don't know, check for version-specific + * mount options. + */ + if (mi->version == 0) { + if (po_contains(mi->options, "mounthost") || + po_contains(mi->options, "mountaddr") || + po_contains(mi->options, "mountvers") || + po_contains(mi->options, "mountproto")) + mi->version = 3; + } + /* * If enabled, see if the default version was * set in the config file */ nfs_default_version(mi); + + return 1; +} + +/* + * Set up mandatory non-version specific NFS mount options. + * + * Returns 1 if successful; otherwise zero. + */ +static int nfs_validate_options(struct nfsmount_info *mi) +{ + struct sockaddr *sap = &mi->address.sa; + + if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) + return 0; + + mi->salen = sizeof(mi->address); + if (!nfs_name_to_address(mi->hostname, sap, &mi->salen)) + return 0; + + if (!nfs_set_version(mi)) + return 0; if (!nfs_append_sloppy_option(mi->options)) return 0; @@ -350,10 +378,13 @@ static int nfs_extract_server_addresses(struct mount_options *options, } 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"); @@ -370,20 +401,14 @@ static int nfs_construct_new_options(struct mount_options *options, po_remove_all(options, "proto"); po_remove_all(options, "udp"); po_remove_all(options, "tcp"); - switch (nfs_pmap->pm_prot) { - case IPPROTO_TCP: - snprintf(new_option, sizeof(new_option) - 1, - "proto=tcp"); - if (po_append(options, new_option) == PO_FAILED) - return 0; - break; - case IPPROTO_UDP: - snprintf(new_option, sizeof(new_option) - 1, - "proto=udp"); - if (po_append(options, new_option) == PO_FAILED) - return 0; - break; - } + 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; po_remove_all(options, "port"); if (nfs_pmap->pm_port != NFS_PORT) { @@ -400,20 +425,14 @@ static int nfs_construct_new_options(struct mount_options *options, return 0; po_remove_all(options, "mountproto"); - switch (mnt_pmap->pm_prot) { - case IPPROTO_TCP: - snprintf(new_option, sizeof(new_option) - 1, - "mountproto=tcp"); - if (po_append(options, new_option) == PO_FAILED) - return 0; - break; - case IPPROTO_UDP: - snprintf(new_option, sizeof(new_option) - 1, - "mountproto=udp"); - if (po_append(options, new_option) == PO_FAILED) - return 0; - break; - } + 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, @@ -440,12 +459,12 @@ static int nfs_construct_new_options(struct mount_options *options, static int nfs_rewrite_pmap_mount_options(struct mount_options *options) { - struct sockaddr_storage nfs_address; - struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address; + union nfs_sockaddr nfs_address; + struct sockaddr *nfs_saddr = &nfs_address.sa; socklen_t nfs_salen = sizeof(nfs_address); struct pmap nfs_pmap; - struct sockaddr_storage mnt_address; - struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address; + union nfs_sockaddr mnt_address; + struct sockaddr *mnt_saddr = &mnt_address.sa; socklen_t mnt_salen = sizeof(mnt_address); struct pmap mnt_pmap; char *option; @@ -489,7 +508,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) return 0; } - if (!nfs_construct_new_options(options, &nfs_pmap, &mnt_pmap)) { + if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap, + mnt_saddr, &mnt_pmap)) { errno = EINVAL; return 0; } @@ -580,7 +600,7 @@ out_fail: */ static int nfs_try_mount_v4(struct nfsmount_info *mi) { - struct sockaddr *sap = (struct sockaddr *)&mi->address; + struct sockaddr *sap = &mi->address.sa; struct mount_options *options = po_dup(mi->options); int result = 0; @@ -590,6 +610,18 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) } if (mi->version == 0) { + if (po_contains(options, "mounthost") || + po_contains(options, "mountaddr") || + po_contains(options, "mountvers") || + po_contains(options, "mountproto")) { + /* + * Since these mountd options are set assume version 3 + * is wanted so error out with EPROTONOSUPPORT so the + * protocol negation starts with v3. + */ + errno = EPROTONOSUPPORT; + goto out_fail; + } if (po_append(options, "vers=4") == PO_FAILED) { errno = EINVAL; goto out_fail; @@ -600,12 +632,13 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) errno = EINVAL; goto out_fail; } + /* * Update option string to be recorded in /etc/mtab. */ if (po_join(options, mi->extra_opts) == PO_FAILED) { errno = ENOMEM; - return 0; + goto out_fail; } result = nfs_sys_mount(mi, options); @@ -634,9 +667,10 @@ static int nfs_try_mount(struct nfsmount_info *mi) /* * To deal with legacy Linux servers that don't * automatically export a pseudo root, retry - * ENOENT errors using version 3 + * ENOENT errors using version 3. And for + * Linux servers prior to 2.6.25, retry EPERM */ - if (errno != ENOENT) + if (errno != ENOENT && errno != EPERM) break; } }