X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=e09aa7c3b470e5322e5b5ebf3115f73eeed947fd;hp=a8b22ce9a0d14bcd89012360cfac52e7f72913bc;hb=9a5293a10551c03b4fb976503dd24da569fcadb3;hpb=911630538580cdaaee1c37cdf1a8b35b8ed6b23f diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index a8b22ce..e09aa7c 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA * */ @@ -49,10 +49,6 @@ #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 @@ -114,7 +110,7 @@ static void nfs_default_version(struct nfsmount_info *mi) } } #else -inline void nfs_default_version(struct nfsmount_info *mi) {} +inline void nfs_default_version(__attribute__ ((unused)) struct nfsmount_info *mi) {} #endif /* MOUNT_CONFIG */ /* @@ -123,10 +119,12 @@ inline void nfs_default_version(struct nfsmount_info *mi) {} * Returns a time_t timeout timestamp, in seconds. */ static time_t nfs_parse_retry_option(struct mount_options *options, - unsigned int timeout_minutes) + const time_t default_timeout) { + time_t timeout_minutes; long tmp; + timeout_minutes = default_timeout; switch (po_get_numeric(options, "retry", &tmp)) { case PO_NOT_FOUND: break; @@ -135,6 +133,7 @@ static time_t nfs_parse_retry_option(struct mount_options *options, timeout_minutes = tmp; break; } + /*FALLTHROUGH*/ case PO_BAD_VALUE: if (verbose) nfs_error(_("%s: invalid retry timeout was specified; " @@ -142,7 +141,7 @@ static time_t nfs_parse_retry_option(struct mount_options *options, break; } - return time(NULL) + (time_t)(timeout_minutes * 60); + return time(NULL) + (timeout_minutes * 60); } /* @@ -303,6 +302,16 @@ static int nfs_set_version(struct nfsmount_info *mi) if (strncmp(mi->type, "nfs4", 4) == 0) mi->version = 4; + /* + * Before 2.6.32, the kernel NFS client didn't + * support "-t nfs vers=4" mounts, so NFS version + * 4 cannot be included when autonegotiating + * while running on those kernels. + */ + if (mi->version == 0 && + linux_version_code() <= MAKE_VERSION(2, 6, 31)) + mi->version = 3; + /* * If we still don't know, check for version-specific * mount options. @@ -333,7 +342,6 @@ static int nfs_validate_options(struct nfsmount_info *mi) { struct addrinfo hint = { .ai_protocol = (int)IPPROTO_UDP, - .ai_flags = AI_ADDRCONFIG, }; sa_family_t family; int error; @@ -429,8 +437,8 @@ static int nfs_construct_new_options(struct mount_options *options, if (po_append(options, new_option) == PO_FAILED) return 0; - po_remove_all(options, "port"); - if (nfs_pmap->pm_port != NFS_PORT) { + if(po_remove_all(options, "port") == PO_FOUND || + nfs_pmap->pm_port != NFS_PORT) { snprintf(new_option, sizeof(new_option) - 1, "port=%lu", nfs_pmap->pm_port); if (po_append(options, new_option) == PO_FAILED) @@ -487,7 +495,6 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) socklen_t mnt_salen = sizeof(mnt_address); unsigned long protocol; struct pmap mnt_pmap; - char *option; /* * Version and transport negotiation is not required @@ -531,6 +538,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) errno = ESPIPE; if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) errno = EOPNOTSUPP; + else if (rpc_createerr.cf_stat == RPC_AUTHERROR) + errno = EACCES; + else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) + errno = ETIMEDOUT; else if (rpc_createerr.cf_error.re_errno != 0) errno = rpc_createerr.cf_error.re_errno; return 0; @@ -561,16 +572,18 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) char *options = NULL; int result; + if (mi->fake) + return 1; + if (po_join(opts, &options) == PO_FAILED) { errno = EIO; return 0; } - if (mi->fake) - return 1; - result = mount(mi->spec, mi->node, mi->type, mi->flags & ~(MS_USER|MS_USERS), options); + free(options); + if (verbose && result) { int save = errno; nfs_error(_("%s: mount(2): %s"), progname, strerror(save)); @@ -641,7 +654,7 @@ out_fail: static int nfs_try_mount_v3v2(struct nfsmount_info *mi) { struct addrinfo *ai; - int ret; + int ret = 0; for (ai = mi->address; ai != NULL; ai = ai->ai_next) { ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen); @@ -654,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) case EHOSTUNREACH: continue; default: - break; + goto out; } } +out: return ret; } @@ -728,7 +742,7 @@ out_fail: static int nfs_try_mount_v4(struct nfsmount_info *mi) { struct addrinfo *ai; - int ret; + int ret = 0; for (ai = mi->address; ai != NULL; ai = ai->ai_next) { ret = nfs_do_mount_v4(mi, ai->ai_addr, ai->ai_addrlen); @@ -740,12 +754,54 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) case EHOSTUNREACH: continue; default: - break; + goto out; } } +out: return ret; } +/* + * Handle NFS version and transport protocol + * autonegotiation. + * + * When no version or protocol is specified on the + * command line, mount.nfs negotiates with the server + * to determine appropriate settings for the new + * mount point. + * + * Returns TRUE if successful, otherwise FALSE. + * "errno" is set to reflect the individual error. + */ +static int nfs_autonegotiate(struct nfsmount_info *mi) +{ + int result; + + result = nfs_try_mount_v4(mi); + if (result) + return result; + + switch (errno) { + case EPROTONOSUPPORT: + /* A clear indication that the server or our + * client does not support NFS version 4. */ + goto fall_back; + case ENOENT: + /* Legacy Linux servers don't export an NFS + * version 4 pseudoroot. */ + goto fall_back; + case EPERM: + /* Linux servers prior to 2.6.25 may return + * EPERM when NFS version 4 is not supported. */ + goto fall_back; + default: + return result; + } + +fall_back: + return nfs_try_mount_v3v2(mi); +} + /* * This is a single pass through the fg/bg loop. * @@ -758,20 +814,8 @@ static int nfs_try_mount(struct nfsmount_info *mi) switch (mi->version) { case 0: - if (linux_version_code() > MAKE_VERSION(2, 6, 31)) { - errno = 0; - result = nfs_try_mount_v4(mi); - if (errno != EPROTONOSUPPORT) { - /* - * To deal with legacy Linux servers that don't - * automatically export a pseudo root, retry - * ENOENT errors using version 3. And for - * Linux servers prior to 2.6.25, retry EPERM - */ - if (errno != ENOENT && errno != EPERM) - break; - } - } + result = nfs_autonegotiate(mi); + break; case 2: case 3: result = nfs_try_mount_v3v2(mi); @@ -867,7 +911,8 @@ static int nfsmount_parent(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (nfs_is_permanent_error(errno)) { + /* retry background mounts when the server is not up */ + if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { mount_error(mi->spec, mi->node, errno); return EX_FAIL; } @@ -902,7 +947,8 @@ static int nfsmount_child(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (nfs_is_permanent_error(errno)) + /* retry background mounts when the server is not up */ + if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) break; if (time(NULL) > timeout) @@ -928,6 +974,26 @@ static int nfsmount_bg(struct nfsmount_info *mi) return nfsmount_child(mi); } +/* + * Usually all that is needed for an NFS remount is to change + * generic mount options like "sync" or "ro". These generic + * options are controlled by mi->flags, not by text-based + * options, and no contact with the server is needed. + * + * Take care with the /etc/mtab entry for this mount; just + * calling update_mtab() will change an "-t nfs -o vers=4" + * mount to an "-t nfs -o remount" mount, and that will + * confuse umount.nfs. + * + * Returns a valid mount command exit code. + */ +static int nfs_remount(struct nfsmount_info *mi) +{ + if (nfs_sys_mount(mi, mi->options)) + return EX_SUCCESS; + return EX_FAIL; +} + /* * Process mount options and try a mount system call. * @@ -944,6 +1010,12 @@ static int nfsmount_start(struct nfsmount_info *mi) if (!nfs_validate_options(mi)) return EX_FAIL; + /* + * Avoid retry and negotiation logic when remounting + */ + if (mi->flags & MS_REMOUNT) + return nfs_remount(mi); + if (po_rightmost(mi->options, nfs_background_opttbl) == 0) return nfsmount_bg(mi); else @@ -960,6 +1032,8 @@ static int nfsmount_start(struct nfsmount_info *mi) * (input and output argument) * @fake: flag indicating whether to carry out the whole operation * @child: one if this is a mount daemon (bg) + * + * Returns a valid mount command exit code. */ int nfsmount_string(const char *spec, const char *node, const char *type, int flags, char **extra_opts, int fake, int child)