]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/nfsumount.c
umount.nfs: Distinguish between nfs4 and nfs mounts
[nfs-utils.git] / utils / mount / nfsumount.c
index b1927de92f156186b3099385ad383c3bfe2b2fad..02d40ff9d2bcb32457f1414b073cbec16cb4f0b9 100644 (file)
@@ -38,6 +38,9 @@
 #include "parse_opt.h"
 #include "parse_dev.h"
 
+#define MOUNTSFILE     "/proc/mounts"
+#define LINELEN                (4096)
+
 #if !defined(MNT_FORCE)
 /* dare not try to include <linux/mount.h> -- lots of errors */
 #define MNT_FORCE 1
@@ -242,6 +245,91 @@ static int nfs_umount23(const char *devname, char *string)
        return result;
 }
 
+/*
+ * Detect NFSv4 mounts.
+ *
+ * Consult /proc/mounts to determine if the mount point
+ * is an NFSv4 mount.  The kernel is authoritative about
+ * what type of mount this is.
+ *
+ * Returns 1 if "mc" is an NFSv4 mount, zero if not, and
+ * -1 if some error occurred.
+ */
+static int nfs_umount_is_vers4(const struct mntentchn *mc)
+{
+       char buffer[LINELEN], *next;
+       int retval;
+       FILE *f;
+
+       if ((f = fopen(MOUNTSFILE, "r")) == NULL) {
+               fprintf(stderr, "%s: %s\n",
+                       MOUNTSFILE, strerror(errno));
+               return -1;
+       }
+
+       retval = -1;
+       while (fgets(buffer, sizeof(buffer), f) != NULL) {
+               char *device, *mntdir, *type, *flags;
+               struct mount_options *options;
+               char *line = buffer;
+
+               next = strchr(line, '\n');
+               if (next != NULL)
+                       *next = '\0';
+
+               device = strtok(line, " \t");
+               if (device == NULL)
+                       continue;
+               mntdir = strtok(NULL, " \t");
+               if (mntdir == NULL)
+                       continue;
+               if (strcmp(device, mc->m.mnt_fsname) != 0 &&
+                   strcmp(mntdir, mc->m.mnt_dir) != 0)
+                       continue;
+
+               type = strtok(NULL, " \t");
+               if (type == NULL)
+                       continue;
+               if (strcmp(type, "nfs4") == 0)
+                       goto out_nfs4;
+
+               flags = strtok(NULL, " \t");
+               if (flags == NULL)
+                       continue;
+               options = po_split(flags);
+               if (options != NULL) {
+                       unsigned long version;
+                       int rc;
+
+                       rc = nfs_nfs_version(options, &version);
+                       po_destroy(options);
+                       if (rc && version == 4)
+                               goto out_nfs4;
+               }
+
+               goto out_nfs;
+       }
+       if (retval == -1)
+               fprintf(stderr, "%s was not found in %s\n",
+                       mc->m.mnt_dir, MOUNTSFILE);
+
+out:
+       fclose(f);
+       return retval;
+
+out_nfs4:
+       if (verbose)
+               fprintf(stderr, "NFSv4 mount point detected\n");
+       retval = 1;
+       goto out;
+
+out_nfs:
+       if (verbose)
+               fprintf(stderr, "Legacy NFS mount point detected\n");
+       retval = 0;
+       goto out;
+}
+
 static struct option umount_longopts[] =
 {
   { "force", 0, 0, 'f' },
@@ -365,13 +453,22 @@ int nfsumount(int argc, char *argv[])
 
        ret = EX_SUCCESS;
        if (mc) {
-               if (!lazy && strcmp(mc->m.mnt_type, "nfs4") != 0)
-                       /* We ignore the error from nfs_umount23.
-                        * If the actual umount succeeds (in del_mtab),
-                        * we don't want to signal an error, as that
-                        * could cause /sbin/mount to retry!
-                        */
-                       nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts);
+               if (!lazy) {
+                       switch (nfs_umount_is_vers4(mc)) {
+                       case 0:
+                               /* We ignore the error from nfs_umount23.
+                                * If the actual umount succeeds (in del_mtab),
+                                * we don't want to signal an error, as that
+                                * could cause /sbin/mount to retry!
+                                */
+                               nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts);
+                               break;
+                       case 1:
+                               break;
+                       default:
+                               return EX_FAIL;
+                       }
+               }
                ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir);
        } else if (*spec != '/') {
                if (!lazy)