summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mtab.c37
-rw-r--r--tests/gnu/fstype_umount.out0
-rw-r--r--tests/gnu/fstype_umount.sh12
3 files changed, 47 insertions, 2 deletions
diff --git a/src/mtab.c b/src/mtab.c
index 39676e5..35ae51d 100644
--- a/src/mtab.c
+++ b/src/mtab.c
@@ -193,18 +193,51 @@ fail:
}
static void bfs_mtab_fill_types(struct bfs_mtab *mtab) {
+ const enum bfs_stat_flags flags = BFS_STAT_NOFOLLOW | BFS_STAT_NOSYNC;
+
for (size_t i = 0; i < darray_length(mtab->entries); ++i) {
struct bfs_mtab_entry *entry = &mtab->entries[i];
+ // It's possible that /path/to/mount was unmounted between bfs_mtab_parse() and bfs_mtab_fill_types().
+ // In that case, the dev_t of /path/to/mount will be the same as /path/to, which should not get its
+ // fstype from the old mount record of /path/to/mount.
+ int fd = -1;
+ const char *path = entry->path;
+ char *dir = xdirname(path);
+ if (dir) {
+ fd = open(dir, O_SEARCH | O_CLOEXEC | O_DIRECTORY);
+ }
+ if (fd >= 0) {
+ path += xbaseoff(path);
+ } else {
+ fd = AT_FDCWD;
+ }
+
struct bfs_stat sb;
- if (bfs_stat(AT_FDCWD, entry->path, BFS_STAT_NOFOLLOW | BFS_STAT_NOSYNC, &sb) != 0) {
- continue;
+ if (bfs_stat(fd, path, flags, &sb) != 0) {
+ goto next;
+ }
+
+ if (fd >= 0) {
+ struct bfs_stat parent;
+ if (bfs_stat(fd, NULL, flags, &parent) == 0) {
+ if (parent.dev == sb.dev) {
+ // Not a mount point any more (or a bind mount, but with the same fstype)
+ goto next;
+ }
+ }
}
struct trie_leaf *leaf = trie_insert_mem(&mtab->types, &sb.dev, sizeof(sb.dev));
if (leaf) {
leaf->value = entry->type;
}
+
+ next:
+ free(dir);
+ if (fd >= 0) {
+ xclose(fd);
+ }
}
mtab->types_filled = true;
diff --git a/tests/gnu/fstype_umount.out b/tests/gnu/fstype_umount.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/gnu/fstype_umount.out
diff --git a/tests/gnu/fstype_umount.sh b/tests/gnu/fstype_umount.sh
new file mode 100644
index 0000000..e817831
--- /dev/null
+++ b/tests/gnu/fstype_umount.sh
@@ -0,0 +1,12 @@
+test "$UNAME" = "Linux" || skip
+
+clean_scratch
+
+mkdir scratch/tmp
+bfs_sudo mount -t tmpfs tmpfs scratch/tmp || skip
+trap "bfs_sudo umount -R scratch/tmp" EXIT
+
+mkdir scratch/tmp/ram
+bfs_sudo mount -t ramfs ramfs scratch/tmp/ram || skip
+
+bfs_diff scratch/tmp -path scratch/tmp -exec "${SUDO[@]}" umount scratch/tmp/ram \; , -fstype ramfs -print