X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=9b8c38fa9b86bb045be854a63e6b4bff3d13bc84;hp=57a4b32df3babb364a717bd560afb35e269e38c3;hb=19c786fc87aba2ecae3072d54ca0a994d5bb997b;hpb=f0d3a4bedccca7cce48296757bc1c8bd59b80828 diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 57a4b32..9b8c38f 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -49,6 +49,10 @@ #include "parse_dev.h" #include "conffile.h" +#ifndef HAVE_DECL_AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif + #ifndef NFS_PROGRAM #define NFS_PROGRAM (100003) #endif @@ -83,8 +87,7 @@ struct nfsmount_info { *node, /* mounted-on dir */ *type; /* "nfs" or "nfs4" */ char *hostname; /* server's hostname */ - union nfs_sockaddr address; - socklen_t salen; /* size of server's address */ + struct addrinfo *address; /* server's addresses */ struct mount_options *options; /* parsed mount options */ char **extra_opts; /* string for /etc/mtab */ @@ -333,17 +336,27 @@ static int nfs_set_version(struct nfsmount_info *mi) */ static int nfs_validate_options(struct nfsmount_info *mi) { - struct sockaddr *sap = &mi->address.sa; + struct addrinfo hint = { + .ai_protocol = (int)IPPROTO_UDP, + .ai_flags = AI_ADDRCONFIG, + }; sa_family_t family; + int error; 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)) + + hint.ai_family = (int)family; + error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); + if (error != 0) { + nfs_error(_("%s: Failed to resolve server %s: %s"), + progname, mi->hostname, gai_strerror(error)); + mi->address = NULL; return 0; + } if (!nfs_set_version(mi)) return 0; @@ -351,7 +364,8 @@ static int nfs_validate_options(struct nfsmount_info *mi) if (!nfs_append_sloppy_option(mi->options)) return 0; - if (!nfs_append_addr_option(sap, mi->salen, mi->options)) + if (!nfs_append_addr_option(mi->address->ai_addr, + mi->address->ai_addrlen, mi->options)) return 0; return 1; @@ -515,6 +529,10 @@ 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; } @@ -545,10 +563,6 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) return 0; } - if (verbose) - printf(_("%s: trying text-based options '%s'\n"), - progname, options); - if (mi->fake) return 1; @@ -562,10 +576,8 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) return !result; } -/* - * For "-t nfs vers=2" or "-t nfs vers=3" mounts. - */ -static int nfs_try_mount_v3v2(struct nfsmount_info *mi) +static int nfs_do_mount_v3v2(struct nfsmount_info *mi, + struct sockaddr *sap, socklen_t salen) { struct mount_options *options = po_dup(mi->options); int result = 0; @@ -575,6 +587,11 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) return result; } + if (!nfs_append_addr_option(sap, salen, options)) { + errno = EINVAL; + goto out_fail; + } + if (!nfs_fix_mounthost_option(options, mi->hostname)) { errno = EINVAL; goto out_fail; @@ -595,6 +612,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) goto out_fail; } + if (verbose) + printf(_("%s: trying text-based options '%s'\n"), + progname, *mi->extra_opts); + if (!nfs_rewrite_pmap_mount_options(options)) goto out_fail; @@ -606,11 +627,36 @@ out_fail: } /* - * For "-t nfs -o vers=4" or "-t nfs4" mounts. + * Attempt a "-t nfs vers=2" or "-t nfs vers=3" mount. + * + * Returns TRUE if successful, otherwise FALSE. + * "errno" is set to reflect the individual error. */ -static int nfs_try_mount_v4(struct nfsmount_info *mi) +static int nfs_try_mount_v3v2(struct nfsmount_info *mi) +{ + struct addrinfo *ai; + int ret; + + for (ai = mi->address; ai != NULL; ai = ai->ai_next) { + ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen); + if (ret != 0) + return ret; + + switch (errno) { + case ECONNREFUSED: + case EOPNOTSUPP: + case EHOSTUNREACH: + continue; + default: + break; + } + } + return ret; +} + +static int nfs_do_mount_v4(struct nfsmount_info *mi, + struct sockaddr *sap, socklen_t salen) { - struct sockaddr *sap = &mi->address.sa; struct mount_options *options = po_dup(mi->options); int result = 0; @@ -638,7 +684,12 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) } } - if (!nfs_append_clientaddr_option(sap, mi->salen, options)) { + if (!nfs_append_addr_option(sap, salen, options)) { + errno = EINVAL; + goto out_fail; + } + + if (!nfs_append_clientaddr_option(sap, salen, options)) { errno = EINVAL; goto out_fail; } @@ -651,6 +702,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) goto out_fail; } + if (verbose) + printf(_("%s: trying text-based options '%s'\n"), + progname, *mi->extra_opts); + result = nfs_sys_mount(mi, options); out_fail: @@ -658,6 +713,33 @@ out_fail: return result; } +/* + * Attempt a "-t nfs -o vers=4" or "-t nfs4" mount. + * + * Returns TRUE if successful, otherwise FALSE. + * "errno" is set to reflect the individual error. + */ +static int nfs_try_mount_v4(struct nfsmount_info *mi) +{ + struct addrinfo *ai; + int ret; + + for (ai = mi->address; ai != NULL; ai = ai->ai_next) { + ret = nfs_do_mount_v4(mi, ai->ai_addr, ai->ai_addrlen); + if (ret != 0) + return ret; + + switch (errno) { + case ECONNREFUSED: + case EHOSTUNREACH: + continue; + default: + break; + } + } + return ret; +} + /* * This is a single pass through the fg/bg loop. * @@ -878,6 +960,7 @@ int nfsmount_string(const char *spec, const char *node, const char *type, struct nfsmount_info mi = { .spec = spec, .node = node, + .address = NULL, .type = type, .extra_opts = extra_opts, .flags = flags, @@ -893,6 +976,7 @@ int nfsmount_string(const char *spec, const char *node, const char *type, } else nfs_error(_("%s: internal option parsing error"), progname); + freeaddrinfo(mi.address); free(mi.hostname); return retval; }