X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=25b206fd4ebe4c1740782621e44528e19b60e298;hp=e277b3d22ac791186c84f6cba11efa80ccae0cde;hb=0de3189d32a183f5e91a6d27a9e8f159216d9473;hpb=c27bf85f0bd41015352468f35dfbf0d431d1e4c5 diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index e277b3d..25b206f 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -80,10 +80,13 @@ struct nfsmount_info { *node, /* mounted-on dir */ *type; /* "nfs" or "nfs4" */ char *hostname; /* server's hostname */ + struct sockaddr_storage address; /* server's address */ + socklen_t salen; /* size of server's address */ struct mount_options *options; /* parsed mount options */ char **extra_opts; /* string for /etc/mtab */ + unsigned long version; /* NFS version */ int flags, /* MS_ flags */ fake, /* actually do the mount? */ child; /* forked bg child? */ @@ -130,12 +133,14 @@ static int nfs_append_generic_address_option(const struct sockaddr *sap, { char address[NI_MAXHOST]; char new_option[512]; + int len; 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)) + len = snprintf(new_option, sizeof(new_option), "%s=%s", + keyword, address); + if (len < 0 || (size_t)len >= sizeof(new_option)) goto out_err; if (po_append(options, new_option) != PO_SUCCEEDED) @@ -254,42 +259,30 @@ static int nfs_append_sloppy_option(struct mount_options *options) } /* - * Set up mandatory NFS mount options. + * 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_storage dummy; - struct sockaddr *sap = (struct sockaddr *)&dummy; - socklen_t salen = sizeof(dummy); + struct sockaddr *sap = (struct sockaddr *)&mi->address; if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) return 0; - if (!nfs_name_to_address(mi->hostname, sap, &salen)) + mi->salen = sizeof(mi->address); + if (!nfs_name_to_address(mi->hostname, sap, &mi->salen)) return 0; - if (strncmp(mi->type, "nfs4", 4) == 0) { - if (!nfs_append_clientaddr_option(sap, salen, mi->options)) - return 0; - } else { - if (!nfs_fix_mounthost_option(mi->options)) - return 0; - if (!mi->fake && !nfs_verify_lock_option(mi->options)) - return 0; - } - - if (!nfs_append_sloppy_option(mi->options)) + if (!nfs_nfs_version(mi->options, &mi->version)) return 0; + if (strncmp(mi->type, "nfs4", 4) == 0) + mi->version = 4; - if (!nfs_append_addr_option(sap, salen, mi->options)) + if (!nfs_append_sloppy_option(mi->options)) return 0; - /* - * Update option string to be recorded in /etc/mnttab - */ - if (po_join(mi->options, mi->extra_opts) == PO_FAILED) + if (!nfs_append_addr_option(sap, mi->salen, mi->options)) return 0; return 1; @@ -418,11 +411,11 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) { struct sockaddr_storage nfs_address; struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address; - socklen_t nfs_salen; + socklen_t nfs_salen = sizeof(nfs_address); struct pmap nfs_pmap; struct sockaddr_storage mnt_address; struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address; - socklen_t mnt_salen; + socklen_t mnt_salen = sizeof(mnt_address); struct pmap mnt_pmap; char *option; @@ -481,17 +474,12 @@ out: * Returns TRUE if successful, otherwise FALSE. * "errno" is set to reflect the individual error. */ -static int nfs_try_mount(struct nfsmount_info *mi) +static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) { char *options = NULL; int result; - if (strncmp(mi->type, "nfs4", 4) != 0) { - if (!nfs_rewrite_pmap_mount_options(mi->options)) - return 0; - } - - if (po_join(mi->options, &options) == PO_FAILED) { + if (po_join(opts, &options) == PO_FAILED) { errno = EIO; return 0; } @@ -513,6 +501,109 @@ static int nfs_try_mount(struct nfsmount_info *mi) return !result; } +/* + * For "-t nfs vers=2" or "-t nfs vers=3" mounts. + */ +static int nfs_try_mount_v3v2(struct nfsmount_info *mi) +{ + struct mount_options *options = po_dup(mi->options); + int result = 0; + + if (!options) { + errno = ENOMEM; + return result; + } + + if (!nfs_fix_mounthost_option(options)) { + errno = EINVAL; + goto out_fail; + } + if (!mi->fake && !nfs_verify_lock_option(options)) { + errno = EINVAL; + goto out_fail; + } + + /* + * Options we negotiate below may be stale by the time this + * file system is unmounted. In order to force umount.nfs + * to renegotiate with the server, only write the user- + * specified options, and not negotiated options, to /etc/mtab. + */ + if (po_join(options, mi->extra_opts) == PO_FAILED) { + errno = ENOMEM; + goto out_fail; + } + + if (!nfs_rewrite_pmap_mount_options(options)) + goto out_fail; + + result = nfs_sys_mount(mi, options); + +out_fail: + po_destroy(options); + return result; +} + +/* + * For "-t nfs -o vers=4" or "-t nfs4" mounts. + */ +static int nfs_try_mount_v4(struct nfsmount_info *mi) +{ + struct sockaddr *sap = (struct sockaddr *)&mi->address; + struct mount_options *options = po_dup(mi->options); + int result = 0; + + if (!options) { + errno = ENOMEM; + return result; + } + + if (!nfs_append_clientaddr_option(sap, mi->salen, options)) { + 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; + } + + result = nfs_sys_mount(mi, options); + +out_fail: + po_destroy(options); + return result; +} + +/* + * This is a single pass through the fg/bg loop. + * + * Returns TRUE if successful, otherwise FALSE. + * "errno" is set to reflect the individual error. + */ +static int nfs_try_mount(struct nfsmount_info *mi) +{ + int result = 0; + + switch (mi->version) { + case 0: + case 2: + case 3: + result = nfs_try_mount_v3v2(mi); + break; + case 4: + result = nfs_try_mount_v4(mi); + break; + default: + errno = EIO; + } + + return result; +} + /* * Distinguish between permanent and temporary errors. *