]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/stropts.c
pdate addres for Free Software Foundation
[nfs-utils.git] / utils / mount / stropts.c
index a8b22ce9a0d14bcd89012360cfac52e7f72913bc..7a2edab45b0a6a475bb4b73105406f1bf745a5b3 100644 (file)
@@ -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
  *
  */
 
 #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;
@@ -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,8 @@ 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_error.re_errno != 0)
                        errno = rpc_createerr.cf_error.re_errno;
                return 0;
@@ -561,16 +570,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 +652,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);
@@ -728,7 +739,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);
@@ -746,6 +757,47 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
        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 +810,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);
@@ -928,6 +968,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 +1004,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 +1026,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)