X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=74224ffdad2a0e477b65b05748384c2d3d51f279;hp=709f0ff24ed3e4d1fd7382c03de2f42919dcd0ee;hb=df6c9d1821585c773297fbfffa1dd315b9c84359;hpb=e1eccc5fc317f73801522b3b498c6dab67b048d2 diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 709f0ff..74224ff 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -35,9 +35,11 @@ #include #include +#include "sockaddr.h" #include "xcommon.h" #include "mount.h" #include "nls.h" +#include "nfsrpc.h" #include "mount_constants.h" #include "stropts.h" #include "error.h" @@ -81,7 +83,7 @@ struct nfsmount_info { *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 */ @@ -93,9 +95,10 @@ struct nfsmount_info { child; /* forked bg child? */ }; -inline void set_default_version(struct nfsmount_info *mi); #ifdef MOUNT_CONFIG -inline void set_default_version(struct nfsmount_info *mi) +static void nfs_default_version(struct nfsmount_info *mi); + +static void nfs_default_version(struct nfsmount_info *mi) { extern unsigned long config_default_vers; /* @@ -108,7 +111,7 @@ inline void set_default_version(struct nfsmount_info *mi) } } #else -inline void set_default_version(struct nfsmount_info *mi) {} +inline void nfs_default_version(struct nfsmount_info *mi) {} #endif /* MOUNT_CONFIG */ /* @@ -203,9 +206,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; @@ -217,21 +220,33 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, } /* - * Resolve the 'mounthost=' hostname and append a new option using - * the resulting address. + * 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) +static int nfs_fix_mounthost_option(struct mount_options *options, + const char *nfs_hostname) { - 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); + 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) - return 1; + if (mounthost == NULL) { + if (nfs_family == mnt_family) + return 1; + mounthost = (char *)nfs_hostname; + } - if (!nfs_name_to_address(mounthost, sap, &salen)) { + if (!nfs_lookup(mounthost, mnt_family, sap, &salen)) { nfs_error(_("%s: unable to determine mount server's address"), progname); return 0; @@ -276,24 +291,12 @@ static int nfs_append_sloppy_option(struct mount_options *options) return 0; 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 = (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; +static int nfs_set_version(struct nfsmount_info *mi) +{ if (!nfs_nfs_version(mi->options, &mi->version)) return 0; + if (strncmp(mi->type, "nfs4", 4) == 0) mi->version = 4; else { @@ -302,11 +305,48 @@ 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 */ - set_default_version(mi); + 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; + sa_family_t family; + + if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) + return 0; + + if (!nfs_nfs_proto_family(mi->options, &family)) + return 0; + mi->salen = sizeof(mi->address); + if (!nfs_lookup(mi->hostname, family, sap, &mi->salen)) + return 0; + + if (!nfs_set_version(mi)) + return 0; if (!nfs_append_sloppy_option(mi->options)) return 0; @@ -348,10 +388,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"); @@ -368,20 +411,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) { @@ -398,20 +435,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, @@ -438,12 +469,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; @@ -484,10 +515,15 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap, nfs_saddr, nfs_salen, &nfs_pmap)) { errno = ESPIPE; + if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) + errno = EOPNOTSUPP; + else if (rpc_createerr.cf_error.re_errno != 0) + errno = rpc_createerr.cf_error.re_errno; 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; } @@ -543,7 +579,7 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) return result; } - if (!nfs_fix_mounthost_option(options)) { + if (!nfs_fix_mounthost_option(options, mi->hostname)) { errno = EINVAL; goto out_fail; } @@ -578,7 +614,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; @@ -588,6 +624,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; @@ -598,12 +646,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); @@ -632,9 +681,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; } }