NFSv4 gladly accepts and mounts "hostname:path" instead of "hostname:/path". NFS also accepts other forms for pathname, but it doesn't use the exact pathname string used for generating /proc/mounts. This causes mount entry mistmatch between /etc/mtab and /proc/mounts files. The former will have the exact given pathname string but the latter will have a modified path name. Signed-off-by: Malahal Naineni <malahal@xxxxxxxxxx> --- utils/mount/nfsumount.c | 94 +++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 83 insertions(+), 11 deletions(-) diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c index 3538d88..54542a5 100644 --- a/utils/mount/nfsumount.c +++ b/utils/mount/nfsumount.c @@ -139,6 +139,88 @@ static int del_mtab(const char *spec, const char *node) return EX_FILEIO; } +/* + * Return normalized path. + * + * Resolve "." and ".." components. Replace multiple slashes with one + * slash. realpath is close but doesn't work for us as the path won't + * exist on the client. + * + * The return string must be freed by the caller. + */ +static char *normpath(const char *path) +{ + const char *ptr, *next, *end; + char *norm; /* result */ + + if (!path) + return NULL; + + norm = malloc(strlen(path)+1); + if (!norm) + return NULL; + + end = path+strlen(path); + *norm = '\0'; /* Make it a NULL string */ + for (ptr = path; ptr < end; ptr = next+1) { + next = strchr(ptr, '/'); + if (!next) + next = end; + int pclen = next - ptr; /* path component length */ + if (strncmp(ptr, ".", pclen) == 0) + continue; + if (strncmp(ptr, "..", pclen) == 0) { + char *tmp = strrchr(norm, '/'); + if (tmp) + *tmp = '\0'; + continue; + } + + /* Add the new component */ + strncat(norm, "/", 1); + strncat(norm, ptr, pclen); + } + + /* + * If there was no component to copy, norm would be null. + * Return "/" in that case + */ + if (*norm == '\0') + strcpy(norm, "/"); + + return norm; +} + +/* + * Detect if the given two entries refer to the same mount entry. + * Usually one entry is from /etc/mtab and the other is from + * /proc/mounts. + */ +static int nfs_same_mount_entry(const struct mntentchn *mc1, + const struct mntentchn *mc2) +{ + char *host1, *host2; + char *path1, *path2; + char *norm1, *norm2; + int retval; + + nfs_parse_devname(mc1->m.mnt_fsname, &host1, &path1); + nfs_parse_devname(mc2->m.mnt_fsname, &host2, &path2); + norm1 = normpath(path1); + norm2 = normpath(path2); + + retval = strcmp(host1, host2) == 0 && strcmp(norm1, norm2) == 0; + + free(host1); + free(host2); + free(path1); + free(path2); + free(norm1); + free(norm2); + + return retval; +} + /* * Detect NFSv4 mounts. * @@ -161,17 +243,7 @@ static int nfs_umount_is_vers4(const struct mntentchn *mc) goto not_found; do { - size_t nlen = strlen(pmc->m.mnt_fsname); - - /* - * It's possible the mount location string in /proc/mounts - * ends with a '/'. In this case, if the entry came from - * /etc/mtab, it won't have the trailing '/' so deal with - * it. - */ - while (pmc->m.mnt_fsname[nlen - 1] == '/') - nlen--; - if (strncmp(pmc->m.mnt_fsname, mc->m.mnt_fsname, nlen) != 0) + if (!nfs_same_mount_entry(pmc, mc)) continue; if (strcmp(pmc->m.mnt_type, "nfs4") == 0) -- 1.7.8.3 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html