summaryrefslogtreecommitdiffstats
path: root/tests/posix
diff options
context:
space:
mode:
Diffstat (limited to 'tests/posix')
-rw-r--r--tests/posix/L_loops.sh4
-rw-r--r--tests/posix/L_xdev.out10
-rw-r--r--tests/posix/L_xdev.sh22
-rw-r--r--tests/posix/closed_stderr.sh1
-rw-r--r--tests/posix/closed_stdin.out19
-rw-r--r--tests/posix/closed_stdin.sh1
-rw-r--r--tests/posix/closed_stdout.sh1
-rw-r--r--tests/posix/deep.sh4
-rw-r--r--tests/posix/depth_error.out4
-rw-r--r--tests/posix/depth_error.sh14
-rw-r--r--tests/posix/exec_nonexistent.sh8
-rw-r--r--tests/posix/exec_plus_nonexistent.sh7
-rw-r--r--tests/posix/exec_plus_nothing.sh2
-rw-r--r--tests/posix/exec_plus_status.sh3
-rw-r--r--tests/posix/exec_ulimit.out16
-rw-r--r--tests/posix/exec_ulimit.sh2
-rw-r--r--tests/posix/extra_paren.sh2
-rw-r--r--tests/posix/incomplete.sh2
-rw-r--r--tests/posix/missing_paren.sh2
-rw-r--r--tests/posix/name_bracket.sh8
-rw-r--r--tests/posix/newer_broken.out (renamed from tests/posix/newer_link.out)0
-rw-r--r--tests/posix/newer_broken.sh4
-rw-r--r--tests/posix/newer_link.sh1
-rw-r--r--tests/posix/newer_nonexistent.sh2
-rw-r--r--tests/posix/nogroup_ulimit.sh10
-rw-r--r--tests/posix/nouser_ulimit.sh9
-rw-r--r--tests/posix/ok_plus_nothing.sh2
-rw-r--r--tests/posix/overlayfs.out5
-rw-r--r--tests/posix/overlayfs.sh11
-rw-r--r--tests/posix/readdir_error.sh37
-rw-r--r--tests/posix/type_bind_mount.out2
-rw-r--r--tests/posix/type_bind_mount.sh15
-rw-r--r--tests/posix/unionfs.out10
-rw-r--r--tests/posix/unionfs.sh9
-rw-r--r--tests/posix/xdev.out8
-rw-r--r--tests/posix/xdev.sh18
36 files changed, 159 insertions, 116 deletions
diff --git a/tests/posix/L_loops.sh b/tests/posix/L_loops.sh
index f737cea..01b7efc 100644
--- a/tests/posix/L_loops.sh
+++ b/tests/posix/L_loops.sh
@@ -1,4 +1,4 @@
# POSIX says it's okay to either stop or keep going on seeing a filesystem
# loop, as long as a diagnostic is printed
-errors=$(invoke_bfs -L loops 2>&1 >/dev/null)
-[ -n "$errors" ]
+invoke_bfs -L loops >/dev/null 2>"$OUT" && fail
+test -s "$OUT"
diff --git a/tests/posix/L_xdev.out b/tests/posix/L_xdev.out
index 2e80082..788579d 100644
--- a/tests/posix/L_xdev.out
+++ b/tests/posix/L_xdev.out
@@ -1,5 +1,5 @@
-scratch
-scratch/foo
-scratch/foo/bar
-scratch/foo/qux
-scratch/mnt
+.
+./foo
+./foo/bar
+./foo/qux
+./mnt
diff --git a/tests/posix/L_xdev.sh b/tests/posix/L_xdev.sh
index ddbadd8..82d8605 100644
--- a/tests/posix/L_xdev.sh
+++ b/tests/posix/L_xdev.sh
@@ -1,15 +1,13 @@
-skip_unless test "$SUDO"
-skip_if test "$UNAME" = "Darwin"
+test "$UNAME" = "Darwin" && skip
-clean_scratch
-mkdir scratch/{foo,mnt}
-sudo mount -t tmpfs tmpfs scratch/mnt
-ln -s ../mnt scratch/foo/bar
-"$XTOUCH" scratch/mnt/baz
-ln -s ../mnt/baz scratch/foo/qux
+cd "$TEST"
+mkdir foo mnt
-bfs_diff -L scratch -xdev
-ret=$?
+bfs_sudo mount -t tmpfs tmpfs mnt || skip
+defer bfs_sudo umount mnt
-sudo umount scratch/mnt
-return $ret
+ln -s ../mnt foo/bar
+"$XTOUCH" mnt/baz
+ln -s ../mnt/baz foo/qux
+
+bfs_diff -L . -xdev
diff --git a/tests/posix/closed_stderr.sh b/tests/posix/closed_stderr.sh
deleted file mode 100644
index cc746ef..0000000
--- a/tests/posix/closed_stderr.sh
+++ /dev/null
@@ -1 +0,0 @@
-fail invoke_bfs basic >&- 2>&-
diff --git a/tests/posix/closed_stdin.out b/tests/posix/closed_stdin.out
deleted file mode 100644
index a7ccfe4..0000000
--- a/tests/posix/closed_stdin.out
+++ /dev/null
@@ -1,19 +0,0 @@
-basic
-basic/a
-basic/b
-basic/c
-basic/c/d
-basic/e
-basic/e/f
-basic/g
-basic/g/h
-basic/i
-basic/j
-basic/j/foo
-basic/k
-basic/k/foo
-basic/k/foo/bar
-basic/l
-basic/l/foo
-basic/l/foo/bar
-basic/l/foo/bar/baz
diff --git a/tests/posix/closed_stdin.sh b/tests/posix/closed_stdin.sh
deleted file mode 100644
index 6932be8..0000000
--- a/tests/posix/closed_stdin.sh
+++ /dev/null
@@ -1 +0,0 @@
-bfs_diff basic <&-
diff --git a/tests/posix/closed_stdout.sh b/tests/posix/closed_stdout.sh
deleted file mode 100644
index 446bf56..0000000
--- a/tests/posix/closed_stdout.sh
+++ /dev/null
@@ -1 +0,0 @@
-fail invoke_bfs basic >&-
diff --git a/tests/posix/deep.sh b/tests/posix/deep.sh
index 3d1cd60..36a88c0 100644
--- a/tests/posix/deep.sh
+++ b/tests/posix/deep.sh
@@ -1,4 +1,2 @@
-closefrom 4
-
-ulimit -n 16
+ulimit -n $((NOPENFD + 13))
bfs_diff deep -type f -exec bash -c 'echo "${1:0:6}/.../${1##*/} (${#1})"' bash {} \;
diff --git a/tests/posix/depth_error.out b/tests/posix/depth_error.out
index ed0e9a1..7ed5f0d 100644
--- a/tests/posix/depth_error.out
+++ b/tests/posix/depth_error.out
@@ -1,2 +1,2 @@
-scratch
-scratch/foo
+.
+./foo
diff --git a/tests/posix/depth_error.sh b/tests/posix/depth_error.sh
index f770210..db414ba 100644
--- a/tests/posix/depth_error.sh
+++ b/tests/posix/depth_error.sh
@@ -1,11 +1,7 @@
-clean_scratch
-"$XTOUCH" -p scratch/foo/bar
-chmod a-r scratch/foo
+cd "$TEST"
+"$XTOUCH" -p foo/bar
-bfs_diff scratch -depth
-ret=$?
+chmod a-r foo
+defer chmod +r foo
-chmod +r scratch/foo
-clean_scratch
-
-[ $ret -eq $EX_BFS ]
+! bfs_diff . -depth
diff --git a/tests/posix/exec_nonexistent.sh b/tests/posix/exec_nonexistent.sh
index b4e08e0..a9ff052 100644
--- a/tests/posix/exec_nonexistent.sh
+++ b/tests/posix/exec_nonexistent.sh
@@ -1,8 +1,4 @@
# Failure to execute the command should lead to an error message and
# non-zero exit status. See https://unix.stackexchange.com/q/704522/56202
-
-stderr=$(invoke_bfs basic -exec "$TESTS/nonexistent" {} \; 2>&1 >/dev/null)
-[ -n "$stderr" ] || return 1
-
-bfs_diff basic -print -exec "$TESTS/nonexistent" {} \; -print
-(($? == EX_BFS))
+bfs_diff basic -print -exec "$TESTS/nonexistent" {} \; -print 2>"$TEST/err" && fail
+test -s "$TEST/err"
diff --git a/tests/posix/exec_plus_nonexistent.sh b/tests/posix/exec_plus_nonexistent.sh
index f96099e..24582a3 100644
--- a/tests/posix/exec_plus_nonexistent.sh
+++ b/tests/posix/exec_plus_nonexistent.sh
@@ -1,5 +1,2 @@
-stderr=$(invoke_bfs basic -exec "$TESTS/nonexistent" {} + 2>&1 >/dev/null)
-[ -n "$stderr" ] || return 1
-
-bfs_diff basic -exec "$TESTS/nonexistent" {} + -print
-(($? == EX_BFS))
+bfs_diff basic -exec "$TESTS/nonexistent" {} + -print 2>"$TEST/err" && fail
+test -s "$TEST/err"
diff --git a/tests/posix/exec_plus_nothing.sh b/tests/posix/exec_plus_nothing.sh
index ef01968..347722d 100644
--- a/tests/posix/exec_plus_nothing.sh
+++ b/tests/posix/exec_plus_nothing.sh
@@ -1,2 +1,2 @@
# Regression test: don't look OOB for {} +
-fail invoke_bfs basic -exec +
+! invoke_bfs basic -exec +
diff --git a/tests/posix/exec_plus_status.sh b/tests/posix/exec_plus_status.sh
index ea9e5ef..a814c4e 100644
--- a/tests/posix/exec_plus_status.sh
+++ b/tests/posix/exec_plus_status.sh
@@ -1,4 +1,3 @@
# -exec ... {} + should always return true, but if the command fails, bfs
# should exit with a non-zero status
-bfs_diff basic -exec false {} + -print
-(($? == EX_BFS))
+! bfs_diff basic -exec false {} + -print
diff --git a/tests/posix/exec_ulimit.out b/tests/posix/exec_ulimit.out
new file mode 100644
index 0000000..144169e
--- /dev/null
+++ b/tests/posix/exec_ulimit.out
@@ -0,0 +1,16 @@
+64 deep/0/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/1/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/2/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/3/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/4/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/5/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/6/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/7/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/8/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/9/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/A/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/B/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/C/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/D/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/E/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
+64 deep/F/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE
diff --git a/tests/posix/exec_ulimit.sh b/tests/posix/exec_ulimit.sh
new file mode 100644
index 0000000..655fbec
--- /dev/null
+++ b/tests/posix/exec_ulimit.sh
@@ -0,0 +1,2 @@
+ulimit -Sn 64
+bfs_diff deep -type f -exec bash -c 'printf "%d %s\n" $(ulimit -Sn) "${1:0:6}/.../${1##*/}"' bash {} \;
diff --git a/tests/posix/extra_paren.sh b/tests/posix/extra_paren.sh
index cd8e8f8..d15022f 100644
--- a/tests/posix/extra_paren.sh
+++ b/tests/posix/extra_paren.sh
@@ -1 +1 @@
-fail invoke_bfs basic -print \)
+! invoke_bfs basic -print \)
diff --git a/tests/posix/incomplete.sh b/tests/posix/incomplete.sh
index 07b1b61..bca5a13 100644
--- a/tests/posix/incomplete.sh
+++ b/tests/posix/incomplete.sh
@@ -1 +1 @@
-fail invoke_bfs basic \(
+! invoke_bfs basic \(
diff --git a/tests/posix/missing_paren.sh b/tests/posix/missing_paren.sh
index ac8dd60..d906fbe 100644
--- a/tests/posix/missing_paren.sh
+++ b/tests/posix/missing_paren.sh
@@ -1 +1 @@
-fail invoke_bfs basic \( -print
+! invoke_bfs basic \( -print
diff --git a/tests/posix/name_bracket.sh b/tests/posix/name_bracket.sh
index 84a417f..e2f943d 100644
--- a/tests/posix/name_bracket.sh
+++ b/tests/posix/name_bracket.sh
@@ -1,5 +1,9 @@
-# fnmatch() is broken on macOS
-skip_if test "$UNAME" = "Darwin"
+# fnmatch() is broken on some platforms
+case "$UNAME" in
+ Darwin|NetBSD)
+ skip
+ ;;
+esac
# An unclosed [ should be matched literally
bfs_diff weirdnames -name '['
diff --git a/tests/posix/newer_link.out b/tests/posix/newer_broken.out
index d2dcdd1..d2dcdd1 100644
--- a/tests/posix/newer_link.out
+++ b/tests/posix/newer_broken.out
diff --git a/tests/posix/newer_broken.sh b/tests/posix/newer_broken.sh
new file mode 100644
index 0000000..dccaa73
--- /dev/null
+++ b/tests/posix/newer_broken.sh
@@ -0,0 +1,4 @@
+ln -s nowhere "$TEST/broken"
+"$XTOUCH" -h -t "1991-12-14 00:03" "$TEST/broken"
+
+bfs_diff times -newer "$TEST/broken"
diff --git a/tests/posix/newer_link.sh b/tests/posix/newer_link.sh
deleted file mode 100644
index 685ac78..0000000
--- a/tests/posix/newer_link.sh
+++ /dev/null
@@ -1 +0,0 @@
-bfs_diff times -newer times/l
diff --git a/tests/posix/newer_nonexistent.sh b/tests/posix/newer_nonexistent.sh
index 789cadf..5f2da4b 100644
--- a/tests/posix/newer_nonexistent.sh
+++ b/tests/posix/newer_nonexistent.sh
@@ -1 +1 @@
-fail invoke_bfs times -newer times/nonexistent
+! invoke_bfs times -newer times/nonexistent
diff --git a/tests/posix/nogroup_ulimit.sh b/tests/posix/nogroup_ulimit.sh
index 8f758c4..a39dd1f 100644
--- a/tests/posix/nogroup_ulimit.sh
+++ b/tests/posix/nogroup_ulimit.sh
@@ -1,8 +1,2 @@
-closefrom 4
-ulimit -n 16
-
-# -mindepth 18, but POSIX
-path="*/*/*/*/*/*"
-path="$path/$path/$path"
-bfs_diff deep -path "deep/$path" -nogroup
-
+ulimit -n $((NOPENFD + 13))
+bfs_diff deep -type f -nogroup
diff --git a/tests/posix/nouser_ulimit.sh b/tests/posix/nouser_ulimit.sh
index 2777589..a94b8c5 100644
--- a/tests/posix/nouser_ulimit.sh
+++ b/tests/posix/nouser_ulimit.sh
@@ -1,7 +1,2 @@
-closefrom 4
-ulimit -n 16
-
-# -mindepth 18, but POSIX
-path="*/*/*/*/*/*"
-path="$path/$path/$path"
-bfs_diff deep -path "deep/$path" -nouser
+ulimit -n $((NOPENFD + 13))
+bfs_diff deep -type f -nouser
diff --git a/tests/posix/ok_plus_nothing.sh b/tests/posix/ok_plus_nothing.sh
index 7cb7de5..77c7644 100644
--- a/tests/posix/ok_plus_nothing.sh
+++ b/tests/posix/ok_plus_nothing.sh
@@ -1,2 +1,2 @@
# Regression test: don't look OOB for {} +
-fail invoke_bfs basic -ok +
+! invoke_bfs basic -ok +
diff --git a/tests/posix/overlayfs.out b/tests/posix/overlayfs.out
new file mode 100644
index 0000000..b472b56
--- /dev/null
+++ b/tests/posix/overlayfs.out
@@ -0,0 +1,5 @@
+merged
+merged/bar
+merged/baz
+merged/baz/qux
+merged/foo
diff --git a/tests/posix/overlayfs.sh b/tests/posix/overlayfs.sh
new file mode 100644
index 0000000..21ef22f
--- /dev/null
+++ b/tests/posix/overlayfs.sh
@@ -0,0 +1,11 @@
+test "$UNAME" = "Linux" || skip
+
+cd "$TEST"
+"$XTOUCH" -p lower/{foo,bar,baz} upper/{bar,baz/qux}
+
+mkdir -p work merged
+bfs_sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged || skip
+defer bfs_sudo rm -rf work
+defer bfs_sudo umount merged
+
+bfs_diff merged
diff --git a/tests/posix/readdir_error.sh b/tests/posix/readdir_error.sh
new file mode 100644
index 0000000..82fcd17
--- /dev/null
+++ b/tests/posix/readdir_error.sh
@@ -0,0 +1,37 @@
+test "$UNAME" = "Linux" || skip
+
+cd "$TEST"
+mkfifo hang pid wait running
+
+(
+ # Create a zombie process
+ cat hang >/dev/null &
+ # Write the PID to pid
+ echo $! >pid
+ # Don't wait on the zombie process
+ exec cat wait hang >running
+) &
+
+# Kill the parent cat on exit
+defer kill -9 %1
+
+# Read the child PID
+read -r pid <pid
+
+# Make sure the parent cat is running before we kill the child, because bash
+# will wait() on its children
+echo >wait &
+read -r _ <running
+
+# Turn the child into a zombie
+kill -9 "$pid"
+
+# Wait until it's really a zombie
+state=R
+while [ "$state" != "Z" ]; do
+ read -r _ _ state _ <"/proc/$pid/stat"
+done
+
+# On Linux, open(/proc/$pid/net) will succeed but readdir() will fail
+test -r "/proc/$pid/net" || skip
+! invoke_bfs "/proc/$pid/net" >/dev/null
diff --git a/tests/posix/type_bind_mount.out b/tests/posix/type_bind_mount.out
index 6435159..2f06c47 100644
--- a/tests/posix/type_bind_mount.out
+++ b/tests/posix/type_bind_mount.out
@@ -1 +1 @@
-scratch/null
+./null
diff --git a/tests/posix/type_bind_mount.sh b/tests/posix/type_bind_mount.sh
index 445f6ef..97b7305 100644
--- a/tests/posix/type_bind_mount.sh
+++ b/tests/posix/type_bind_mount.sh
@@ -1,12 +1,9 @@
-skip_unless test "$SUDO"
-skip_unless test "$UNAME" = "Linux"
+test "$UNAME" = "Linux" || skip
-clean_scratch
-"$XTOUCH" scratch/{file,null}
-sudo mount --bind /dev/null scratch/null
+cd "$TEST"
+"$XTOUCH" file null
-bfs_diff scratch -type c
-ret=$?
+bfs_sudo mount --bind /dev/null null || skip
+defer bfs_sudo umount null
-sudo umount scratch/null
-return $ret
+bfs_diff . -type c
diff --git a/tests/posix/unionfs.out b/tests/posix/unionfs.out
new file mode 100644
index 0000000..28c4ec1
--- /dev/null
+++ b/tests/posix/unionfs.out
@@ -0,0 +1,10 @@
+.
+./lower
+./lower/bar
+./lower/baz
+./lower/foo
+./upper
+./upper/bar
+./upper/baz
+./upper/baz/qux
+./upper/foo
diff --git a/tests/posix/unionfs.sh b/tests/posix/unionfs.sh
new file mode 100644
index 0000000..94d3929
--- /dev/null
+++ b/tests/posix/unionfs.sh
@@ -0,0 +1,9 @@
+[[ "$UNAME" == *BSD* ]] || skip
+
+cd "$TEST"
+"$XTOUCH" -p lower/{foo,bar,baz} upper/{bar,baz/qux}
+
+bfs_sudo mount -t unionfs -o below lower upper || skip
+defer bfs_sudo umount upper
+
+bfs_diff .
diff --git a/tests/posix/xdev.out b/tests/posix/xdev.out
index f7839fb..6253434 100644
--- a/tests/posix/xdev.out
+++ b/tests/posix/xdev.out
@@ -1,4 +1,4 @@
-scratch
-scratch/foo
-scratch/foo/bar
-scratch/mnt
+.
+./foo
+./foo/bar
+./mnt
diff --git a/tests/posix/xdev.sh b/tests/posix/xdev.sh
index 4591940..c59c5c8 100644
--- a/tests/posix/xdev.sh
+++ b/tests/posix/xdev.sh
@@ -1,13 +1,11 @@
-skip_unless test "$SUDO"
-skip_if test "$UNAME" = "Darwin"
+test "$UNAME" = "Darwin" && skip
-clean_scratch
-mkdir scratch/{foo,mnt}
-sudo mount -t tmpfs tmpfs scratch/mnt
-"$XTOUCH" scratch/foo/bar scratch/mnt/baz
+cd "$TEST"
+mkdir foo mnt
-bfs_diff scratch -xdev
-ret=$?
+bfs_sudo mount -t tmpfs tmpfs mnt || skip
+defer bfs_sudo umount mnt
-sudo umount scratch/mnt
-return $ret
+"$XTOUCH" foo/bar mnt/baz
+
+bfs_diff . -xdev